使用乘法执行整数除法



查看编译器生成的x86程序集,我注意到(无符号)整数除法有时实现为整数乘法。这些优化似乎遵循以下形式

value / n => (value * ((0xFFFFFFFF / n) + 1)) / 0x100000000

例如,执行除以 9:

12345678 / 9 = (12345678 * 0x1C71C71D) / 0x100000000

除以 3 将使用乘法与 0x55555555 + 1 ,依此类推。

利用mul指令将结果的高部分存储在edx寄存器中的事实,可以使用具有魔术值的单个乘法获得除法的最终结果。(尽管此优化有时与末尾的按位移位结合使用。

我想了解一下它的实际工作原理。此方法何时有效?为什么必须在我们的"幻数"中添加 1?

该方法称为"除以不变乘法"。

您看到的常数实际上是倒数的近似值。

因此,与其计算:

N / D = Q

你改为做这样的事情:

N * (1/D) = Q

其中1/D是可以预先计算的倒数。

从根本上说,倒数是不精确的,除非D是2的幂。因此,会涉及一些舍入误差。您看到的+1用于纠正舍入误差。


最常见的例子是除以 3:

N / 3 = (N * 0xaaaaaaab) >> 33

哪里0xaaaaaaab = 2^33 / 3 + 1.

这种方法将推广到其他除数。

最新更新