==
减法:
按照数学定义 x-y 等价于 x+(-y), 所以实现上先将 y 求其对应负数, 而后
用已经实现的加法就可完成减法的运算. 算法
所以只须要研究如何求负数便可. rem
求一个数的负数 neg(), 等于将该数字二进制求补码, 也即先反转全部二进制位
而后加上 1. 代码示例以下: 数学
int carry = 1; // 整个数反转后要+1, 因此初始为 1.
for (int i = 0; i < len; ++i) {
carry += (~src.arr[i]) // 二进制反转, ~ 为求反运算.
& 0xff; // 取 byte 部分.
dest[i] = (byte)carry; // 取低位.
carry >>>= 8; // 进位部分
}
boolean overflow = src[len-1] < 0 && dest[len-1] < 0;
if (overflow) dest[len++] = 0;
return new mp_int (len, dest); // 结果 原理
关于 overflow 标志, 举例如数字 = -128=0x80 时, 取反获得 0x7F, 加上1
又回到 0x80, 此时称为 overflow. 这种状况只发生在最高位为 1, 其他全部位
都是 0 的状况. 此时求负以后的数字要当作无符号数看待, 在最高位补上一个 0
(dest[len++] = 0 即为最高位补0). 二进制
==
乘法
为简化问题, 只考虑正数的乘法, 若是x,y 有负数, 先对齐求负转换为正数,
而后再进行乘法. 方法
相似于咱们手写数字乘法竖式, 咱们将各个位逐个相乘, 并累加到结果上,
有进位的继续向高一位累加. 这样一个 m位的数字乘上一个 n位的数字, 获得的
结果为 m*n 位的. 伪代码以下: word
mul(byte[] dest, byte[] x, int xlen, byte[] y, int ylen)
// 计算乘积, 使得 dest = x*y
for (int i = 0; i < ylen; ++i) {
int yword = (int)y[i] & 0xff; // 取y 的第 i位.
int carry = 0; // 进位.
for (int j = 0; j < xlen; ++j) {
carry += ((int)x[i] & 0xff) // 取 x 的第 j 位.
* yword ; // 乘上 y 的第 i 位
+ ((int)dest[i+j] & 0xff); // 加上现有第 i+j 位.
dest[i+j] = (byte) carry; // 更新到结果的第 i+j 位
carry >>>= 8; // 获得第 i+j+1 位的进位. 这个进位可能大于 1
}
dest[i+xlen] = (byte)carry;
} 注释
这里细节可能有些忽略的地方, 但基本原理是每位分别乘积, 最后累加到一块儿. 移动
==
除法
除法的实现代码看起来是比较复杂. 不如直接看书理解原理容易. 实际上我看
的 Kawa 源代码中也注释写着使用的是基本的 Knuth 经典算法的公式. 因此为
学原理, 这里仍是看书更直接些.
为实现除法 u/v, 咱们先排除掉一些简单的状况:
1. 若是 u < v, 则除法 u/v 的商(quotient)=0, 余数(remainder)=u
2. 排除掉 u = v 的状况. 源代码
如今 u > v, 先考虑 u 只比 v 多一位的状况, 此时 u 表示为
(u_n, u_(n-1), ... , u_1, u_0) 这里用下划线这里表示后面跟着下标的意思.
v 表示为 (v_(n-1), v_(n-2), ..., v_1, v_0) 的形式. 若是找到了求
这种形式的商, 也就能为更多位的 u 进行计算了, 由于能够先计算前 n+1 位,
而后再进一步加上后面的位.
设 u = q*v + r; 则这里 q 表示商, 知足 q < b; 而 r 表示余数, 知足 r < v.
要推测 q 的值的合理方法是, 使用 u,v 的最高位的有效数字进行推测.
这里最高位的有效数字, 指高位的 m 个二进制位, 其中最高位是1. (这里都按照
无符号整数看待, 最高位为1 仍然是正数). m 越多, 推测的就越准确.
Knuth 的书上还有这方面的定理, 以及...证实. 这里说明, 要有好的数学功底,
才能真正理解这背后的原理, 而我数学已经不少年不学从而忘得差很少了.
所以这里, 咱们努力理解这些原理, 实在理解不了, 就只能照用了.
要获得最高位的有效数字, 在代码中我看到是使用了向左移位的方法, 将有效
位都移动到了高位. 这样计算试验商 q 比较准确些. 而且这里使用 int 型而非
byte 型, 可使二进制位数 m 较多, 从而 q 准确性更高. 实际书上证实了
q'-2 <= q <= q', 这里 q' 表示试验商. 也即试验的商 q' 的偏差毫不大于 2.
到这里, 咱们基本能够理解算法D(整数除法)的核心部分: 试商的求取了. 算法D 系统的给出了求取试商以及修正方法, 而后其它一些步骤, 这里略, 请 参考原书.