在C++中将浮点数强制转换为整数,做了些什么——ftol注释

在vc中,如果你将一个浮点数强制转换成一个整数,比如int i = (int)f;

那么简单的一句话,就有可能被编译器转换为一个函数调用,就是_ftol2,参数为一个浮点数,开始函数调用前,该参数已经被压入浮点寄存器堆栈st(0)中,取整规则为去尾,即偏向0。

浮点寄存器堆栈一共从st(0)到st(7),可以看做一个循环队列。堆栈顶端为st(0),st(0)简称st

 

_ftol2:
0040142C 55                    push         ebp  
0040142D 8B EC                 mov          ebp,esp 
0040142F 83 EC 20              sub          esp,20h                    //堆栈上空出20h个字节,用于存储临时变量
00401432 83 E4 F0              and          esp,0FFFFFFF0h             //将esp对齐到16字节
00401435 D9 C0                 fld          st(0)                      //压入st(0),原先的st(0)变为st(1),这样st(1) == st(0)
00401437 D9 54 24 18           fst          dword ptr [esp+18h]        //将st(0)转换为单精度(dword) 保存倒[esp + 18h]位置

0040143B DF 7C 24 10           fistp        qword ptr [esp+10h]        //将st(0)取整保存到[esp+10h]位置,这个结果是64位的(qword),结果偏0还是远离0应该取决于协处理器msw。同时弹出st(0),原先的st(1)变为st(0)
0040143F DF 6C 24 10           fild         qword ptr [esp+10h]        //将刚才取整的结果load到st(0)。现在st(1)是原值,st(0)是取整后的值
00401443 8B 54 24 18           mov          edx,dword ptr [esp+18h]    //取原值单精度版到edx
00401447 8B 44 24 10           mov          eax,dword ptr [esp+10h]    //取64位取整结果的低32位
0040144B 85 C0                 test         eax,eax 
0040144D 74 3C                 je           integer_QnaN_or_zero (0040148B) //如果eax位0,则该浮点数可能是0或者NAN

arg_is_not_integer_QnaN:
0040144F DE E9                 fsubp        st(1),st    //原值减去取整后的结果,结果在st(0)中。取整结果如果偏0, 原值为正结果得正,原值为负结果得负; 取整结果如果远离0, 原值为正结果得负,原值为负结果得正
00401451 85 D2                 test         edx,edx     //测试原浮点数的单精度格式
00401453 79 1E                 jns          positive (00401473)  //如果原值是非负数则跳转,以下是负数的处理方法
00401455 D9 1C 24              fstp         dword ptr [esp]      //将减法结果保存到[esp]位置,弹出栈顶元素,st(0)变为原值
00401458 8B 0C 24              mov          ecx,dword ptr [esp]  
0040145B 81 F1 00 00 00 80     xor          ecx,80000000h        //减法结果最高位取反,其余位不变

00401461 81 C1 FF FF FF 7F     add          ecx,7FFFFFFFh        //如果减法结果为正,则最高为取反后为1,再加7FFFFFFFh必定CF=1,即远离0;如果减法结果为0或者负数,则CF=0,即偏向0
00401467 83 D0 00              adc          eax,0                //对于负浮点数,取整结果远离0(CF=1)就是多减了1,需要加1,让结果偏0;取整结果如果偏向0(CF=0),结果eax加上CF和0,值仍然不变
0040146A 8B 54 24 14           mov          edx,dword ptr [esp+14h]

0040146E 83 D2 00              adc          edx,0 
00401471 EB 2C                 jmp          localexit (0040149F)

positive:
00401473 D9 1C 24              fstp         dword ptr [esp]      //注释同上

00401476 8B 0C 24              mov          ecx,dword ptr [esp] 
00401479 81 C1 FF FF FF 7F     add          ecx,7FFFFFFFh

0040147F 83 D8 00              sbb          eax,0                //对于正浮点数,取整远离0(CF=1)就是多加了1,需要减1,让结果偏0;取整结果如果偏向0(CF=0),结果减去CF和0,值仍然不变
00401482 8B 54 24 14           mov          edx,dword ptr [esp+14h]

00401486 83 DA 00              sbb          edx,0 
00401489 EB 14                 jmp          localexit (0040149F)

integer_QnaN_or_zero:      //对于0或者NAN
0040148B 8B 54 24 14           mov          edx,dword ptr [esp+14h]  //取64位取整结果的高32位
0040148F F7 C2 FF FF FF 7F     test         edx,7FFFFFFFh            //测试高字的低31位,
00401495 75 B8                 jne          arg_is_not_integer_QnaN (0040144F)
00401497 D9 5C 24 18           fstp         dword ptr [esp+18h]
0040149B D9 5C 24 18           fstp         dword ptr [esp+18h]

localexit:
0040149F C9                    leave
004014A0 C3                    ret          //结果在eax中


  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值