huyutian

他强由他强,清风拂山岗;他横由他横,明月照大江。他自狠来他自恶,我自一口真气足

  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理 ::
  20 随笔 :: 47 文章 :: 22 评论 :: 0 Trackbacks
今天调试一个程序时遇到了一段奇怪的汇编代码
        mov     eax, 68DB8BADh
        push    edi
        movsx   ecx, word ptr [esi+0Eh]
        imul    ecx
        sar     edx, 0Ch
        mov     eax, edx
        shr     eax, 1Fh
        add     edx, eax
看了半天也没看明白,主要是这个68DB8BADh出现的很突兀,与前后代码在逻辑上都不相关联。到网上搜了下,还居然找到了答案。原来这是一段编译器将除法优化为乘法运算的典型代码。众所周知,除法是最耗CPU的,能够转化为等效的乘法就要快得多了。但不是每次除法都能这么优化的。对于一些特定数作为被除数时,这种优化还是很有效的。
http://www.thesolver.it/Manuali/Factotum/source/076.htm这里列出了一些典型数的除法转换表。

这个表是32位运算下除法转换为乘法的一些案例。比如68DB8BADh这个魔术数就是用来转换除以625的。要计算x/625 = (x * 68DB8BADh) >>8.所以上面的代码其实就是计算[esi +0Eh] / 10000.
下面这个表是64位运算时除法转换为乘法的一些魔术数,摘录在此,以防备忘

如果想搞清楚相关的运算原理可以看该网站的Chapter 10. Integer Division by Constants ,网址是http://www.thesolver.it/Manuali/Factotum/source/062.htm
大家也可以自己编一段小程序验证一下。
 1 #include <stdio.h>
 2 
 3 int main(int argc, char* argv[])
 4 {
 5     int a = getchar();
 6     int b = a / 10000;
 7     printf("a=%d\nb=a/10000=%d\n", a, b);
 8     return 0;
 9 }
10 
在VC2008下设置项目编译属性Assembler Output,选择输出汇编代码,看看编译出来的代码与上面的完全一致。
posted on 2010-08-25 22:26 胡雨田 阅读(3073) 评论(0)  编辑 收藏 引用 所属分类: 编程技巧

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理