GMP如何识别有符号整数?mpz_tdiv_q能否安全处理负整数?
GMP库负数处理与mpz_tdiv_q使用疑问
我知道将两个大正整数或无符号整数传入mpz_tdiv_q()做除法是安全的,但有几个疑问:
- 当通过
mpz_roinit_n()把8字节内存单元转换成存储大负整数的mpz_t时,GMP是怎么识别它是负数的? - 这种带负数的
mpz_t能不能安全传入mpz_tdiv_q()做除法计算? - GMP里的大整数是按完整存储单元存的,比如120位会占两个连续的64位存储单元。如果是负数的话,要不要先扩展符号位,再调用
mpz_tdiv_q()?
附上代码示例:
uint64_t ext_lhs[2]; uint64_t ext_rhs[2]; mpn_copyi(ext_lhs, lhs, 2); mpn_copyi(ext_rhs, rhs, 2); // 是否需要对最高位做符号位扩展? if(overwidth){ svs_sext_to_bv64x_from_bv64x(ext_lhs, 2, width, lhs, 2 - 1, overwidth); svs_sext_to_bv64x_from_bv64x(ext_rhs, 2, width, rhs, 2 - 1, overwidth); } mpz_t res, left, right; mpz_init(res); mpz_tdiv_q(res, mpz_roinit_n(left, ext_lhs, 2), mpz_roinit_n(right, ext_rhs, 2));
问题解答
1. GMP如何识别mpz_roinit_n()创建的负数?
GMP的mpz_t结构里单独存储符号位,和底层的mpn多精度数字数组是分离的。mpz_roinit_n()只会读取你传入的uint64_t数组作为无符号数字位,默认把这个mpz_t标记为正数,它不会自动解析数组里的补码负数。
如果你的内存单元存的是补码形式的负数,必须手动设置符号位:要么调用mpz_neg()翻转符号,要么改用mpz_import()并指定符号参数,才能让GMP识别这是一个负数。
2. 带负数的mpz_t能否安全传入mpz_tdiv_q()?
完全可以。mpz_tdiv_q()支持正负整数的截断除法(向零取整),只要你的mpz_t符号位与数字位匹配(即正确表示了目标负数),传入后不会有安全问题,运算结果符合GMP的除法规则。
3. 负数是否需要先扩展符号位?
这取决于你的原始数据长度:
- 如果原始数据是
width位的补码负数,且width小于目标存储的总位数(比如示例里的120位),必须做符号位扩展。因为GMP的mpn数组按无符号存储,直接把短位补码负数放到长位数组里,高位会是0,GMP会把它当成超大正数,后续除法结果完全错误。 - 如果原始数据已经是目标位数的完整补码负数,那不需要扩展,直接传入后手动设置符号位即可。
你代码里的svs_sext_to_bv64x_from_bv64x函数就是做符号位扩展的,这一步是必要的,不能省略。另外要注意:mpz_roinit_n()创建的mpz_t是只读的,不能修改数字位,但可以修改符号位,所以正确流程是:先做符号位扩展,再用mpz_roinit_n()初始化,最后根据原始数据的符号调用mpz_neg()设置正确符号,再传入mpz_tdiv_q()计算。
内容的提问来源于stack exchange,提问作者piggogo
相关产品推荐
相关产品推荐

