也称为快速乘法
将被乘数除以2,乘数乘以2,如果被乘数除以2 有余数,则将乘数累加到结果中。
我们使用一个例子来逐步展开来看看这个过程。
计算 78 × 57
第一步,将 78 确定为被乘数,57 确定为乘数,这个顺序可以随意;
累计结果是 sum, a = 78, b = 57, 列表表示计算过程:
a | b | 余数 | sum |
---|---|---|---|
78 | 57 | 0 | 0 |
39 | 114 | 1 | 114 |
19 | 228 | 1 | 342 |
9 | 456 | 1 | 798 |
4 | 912 | 0 | 798 |
2 | 1824 | 0 | 798 |
1 | 3648 | 1 | 4446 |
实际上,上面的乘法原理可以表示成
78 = 64 + 8 + 4 + 2 = 2^6 + 2^3 + 2^2 + 2^1
78 × 57 = (2^6 + 2^3 + 2^2 + 2^1) * 57 = 57 << 6 + 57 << 3 + 57 << 2 + 57 << 1
任何正整数可以分解成这样:
于是 a × b 可以表示这样:
对每个 项,相当于将 b 左移 位。
因此俄罗斯农民算法的本质是二进制拆分,然后将有 1 的 位进行累计
上面的表的除2取余的过程,实际上就是二进制拆分的过程。
写成 C++ 程序
int multiply(int a, int b) {
int s = 0;
while (a >= 1) {
if (a % 2) {
s += b;
// s %= M 如果要取模在这里增加模运算
}
a >>= 1;
b <<= 1;
}
return s;
}
这个算法由于使用了移位运算,速度非常快。应用场景用于移位取模,两数相乘非常大,超过数据类型的表示范围,但是取模之后还在范围内,那么可以用这个算法对累计和每次取模,可以快速计算出一个大数对某个数的模运算的结果。
不要用这个算法代替乘法运算符 例如用C++ 重载的特性取代,没有什么性能优化,也容易产生数据溢出和截断的 bug
网友评论