我认为诀窍如下(我打算以 10 为底,因为它更容易,但原则应该成立)
假设你在乘法a*b mod 10000-1
,并且
a = 1234 = 12 * 100 + 34
b = 5432 = 54 * 100 + 32
现在a*b = 12 * 54 * 10000 + 34 * 54 * 100 + 12 * 32 * 100 + 34 * 32
12 * 54 * 10000 = 648 * 10000
34 * 54 * 100 = 1836 * 100
12 * 32 * 100 = 384 * 100
34 * 32 = 1088
从x * 10000 ≡ x (mod 10000-1)
[1] 开始,第一项和最后一项变为 648+1088。第二个和第三个术语是“技巧”的来源。请注意:
1836 = 18 * 100 + 36
1836 * 100 ≡ 18 * 10000 + 3600 ≡ 3618 (mod 10000-1).
这本质上是一个循环移位。给出 648 + 3618 + 8403 + 1088 的结果。还要注意,在所有情况下,相乘的数字都 < 10000(因为 a < 100 和 b < 100),所以如果你只能将多个 2 位数字放在一起,这是可以计算的, 并添加它们。
在二进制中,它会以类似的方式工作。
以 a 和 b 开头,都是 32 位。假设您想将它们相乘 mod 2^31 - 1,但您只有一个 16 位乘法器(给出 32 位)。该算法将是这样的:
a = 0x12345678
b = 0xfedbca98
accumulator = 0
for (x = 0; x < 32; x += 16)
for (y = 0; y < 32; y += 16)
// do the multiplication, 16-bit * 16-bit = 32-bit
temp = ((a >> x) & 0xFFFF) * ((b >> y) & 0xFFFF)
// add the bits to the accumulator, shifting over the right amount
total_bits_shifted = x + y
for (bits = 0; bits < total_bits_shifted + 32; bits += 31)
accumulator += (temp >> (bits - total_bits_shifted)) & 0x7FFFFFFF
// do modulus if it overflows
if (accumulator > 0x7FFFFFFFF)
accumulator = (accumulator >> 31) + (accumulator & 0x7FFFFFFF);
为时已晚,因此其中的累加器部分可能无法正常工作。我认为原则上它是正确的。有人可以随意编辑它以使其正确。
展开,这也相当快,我猜这也是 PRNG 使用的。
[1]: x*10000 ≡ x*(9999+1) ≡ 9999*x + x ≡ x (mod 9999)