上一篇博文简单谈了大整数算法的一些最基本操作,接下来要介绍一些相对高级一点点的操作:比较操作。比较操作分成三种:绝对值比较,有符号数比较,多精度数和单精度数比较。
约定:所有的比较操作,如果 x > y,返回 1;x == y,返回 0;x < y,返回 -1。
★ 绝对值比较
绝对值比较操作只比较两个大整数的绝对值大小,比较方法和十进制数的比较是相同的。先比较位数,位数大的绝对值更大,如果位数相同,从高位到低位依次比较两个大整数中相同位的数位大小,如果比较到某一位时一个整数的该数位大于另一个整数中相同位置的数位,则该整数更大。
int bn_cmp_abs(const bignum *x, const bignum *y) { size_t i; if(x->used > y->used) return 1; if(x->used < y->used) return -1; //x 和 y 的位数相同,依次比较相同位的大小。 for(i = x->used; i > 0; i--) { if(x->dp[i - 1] > y->dp[i - 1]) return 1; if(x->dp[i - 1] < y->dp[i - 1]) return -1; } return 0; }
★ 有符号数比较
有符号数的比较比绝对值比较稍微复杂一点,但可以总结成一下几类:
1. x 和 y 两个数异号:非负数大于负数。
2. x 和 y 两个数同号:若 x 和 y 都是非负整数,比较 x 和 y 的绝对值大小;若 x 和 y 都是负整数,比较 y 和 x 的绝对值大小。
第一种情况好理解,我就解释一下第二种情况。
当 x >= 0 并且 y >= 0,若 x >= y(x < y),则有 |x| >= |y|(|x| < |y|),所以要比较 x 和 y 的绝对值大小。
当 x < 0 并且 y < 0,若 x >= y(x < y),则有 -x <= -y(-x > -y),即 |x| <= |y|(|x| > |y|),所以要比较 y 和 x 的绝对值大小(反方向执行无符号数比较)。
int bn_cmp_bn(const bignum *x, const bignum *y) { if(x->sign == 1 && y->sign == -1) return 1; if(y->sign == 1 && x->sign == -1) return -1; if(x->sign == 1) return bn_cmp_abs(x, y); else return bn_cmp_abs(y, x); }
★ 多精度数和单精度数比较
简单来说就是将一个大整数与一个有符号的单精度数(bn_sint类型)进行比较。有了前面的大整数与大整数之间的有符号比较操作,这里就不需要再写一个新的操作了,直接把有符号的单精度数赋值给一个临时的大整数类型变量 t,然后调用bn_cmp_bn函数进行比较。虽然这种带有欺骗性的把戏在一定程度上会损失一点点性能,但可以让编码和计算变得相对简单。
int bn_cmp_int(const bignum *x, const bn_sint y) { bignum t[1]; bn_digit p[1]; p[0] = (y >= 0) ? y : -y; t->sign = (y >= 0) ? 1 : -1; t->used = (y == 0) ? 0 : 1; //注意 bignum 为 0 时,规定 used = 0. t->alloc = 1; t->dp = p; return bn_cmp_bn(x, t); }
★ 总结
比较操作虽然简单,不过在一开始实现的时候还是犯了好几个低级错误,归根结底还是没有考虑好所有情况,编码的时候也不够仔细,所以还是那句老话:细节决定成败。下一篇文章将介绍更高级点的操作:位设置操作。
【回到本系列目录】
版权声明
原创博文,转载必须包含本声明,保持本文完整,并以超链接形式注明作者Starrybird和本文原始地址:http://www.cnblogs.com/starrybird/p/4354703.html