为什么这样复杂的代码是用二的幂来分割一个有符号的整数?
当我用VC ++ 10编译这个代码时:
DWORD ran = rand(); return ran / 4096; 我得到这个反汇编:
 299: { 300: DWORD ran = rand(); 00403940 call dword ptr [__imp__rand (4050C0h)] 301: return ran / 4096; 00403946 shr eax,0Ch 302: } 00403949 ret 
这是干净简洁的,用合理的右移代替了两位的权力。
然而,当我编译这个代码:
 int ran = rand(); return ran / 4096; 
我得到这个反汇编:
 299: { 300: int ran = rand(); 00403940 call dword ptr [__imp__rand (4050C0h)] 301: return ran / 4096; 00403946 cdq 00403947 and edx,0FFFh 0040394D add eax,edx 0040394F sar eax,0Ch 302: } 00403952 ret 
在进行正确的算术移位之前执行一些操作。
那些额外的操作需要什么? 为什么算术转换不够?
原因在于2 ^ n的无符号划分可以非常简单地实现,而有符号划分比较复杂。
 unsigned int u; int v; 
  u / 4096相当于u >> 12 ,表示u所有可能值。 
  v / 4096 不等于v >> 12 – 当v < 0 ,它会发生故障,因为当涉及到负数时,舍入方向不同于移位与除法。 
“额外的操作”补偿了这样的事实,即算术右移将结果向负无穷转,而分割将结果向零转。
 例如, -1 >> 1是-1 ,而-1/2是0 。 
从C标准:
当整数被分解时,/运算符的结果是丢弃任何小数部分的代数商。如果商a / b是可表示的,则expression式(a / b)* b + a%b将等于a; 否则,a / b和a%b的行为都是未定义的。
我们不难想到,一个负值不符合这个规则的例子是纯粹的算术移位。 例如
 (-8191) / 4096 -> -1 (-8191) % 4096 -> -4095 
满足方程,而
 (-8191) >> 12 -> -2 (assuming arithmetic shifting) 
 不是截断,所以-2 * 4096 - 4095肯定不等于-8191。 
 请注意,负数的移位实际上是实现定义的,所以Cexpression式(-8191) >> 12并没有像标准一样正确的结果。