【发布时间】:2016-07-02 13:25:04
【问题描述】:
有一个(相对)众所周知的将 32 位数字除以三的技巧。这个数字可以乘以幻数0x55555556,而不是使用实际昂贵的除法,结果的高 32 位就是我们要寻找的。比如下面的C代码:
int32_t div3(int32_t x)
{
return x / 3;
}
使用 GCC 和 -O2 编译,结果如下:
08048460 <div3>:
8048460: 8b 4c 24 04 mov ecx,DWORD PTR [esp+0x4]
8048464: ba 56 55 55 55 mov edx,0x55555556
8048469: 89 c8 mov eax,ecx
804846b: c1 f9 1f sar ecx,0x1f
804846e: f7 ea imul edx
8048470: 89 d0 mov eax,edx
8048472: 29 c8 sub eax,ecx
8048474: c3 ret
我猜sub 指令负责修复负数,因为它实际上是在参数为负时加 1,否则为 NOP。
但是为什么这行得通?我一直在尝试手动将较小的数字乘以这个掩码的 1 字节版本,但我看不到模式,而且我在任何地方都找不到任何解释。这似乎是一个神秘的魔法数字,任何人都不清楚其来源,就像0x5f3759df一样。
有人能解释一下这背后的算法吗?
【问题讨论】:
-
@PeterO。请告诉我在那个问题(或答案)中,我上面概述的特定算法在哪里得到了解释。
标签: algorithm bit-manipulation arithmetic-expressions