如何在C++中实现浮点转换?(double to float或float to double)

JBL*_*JBL 11 c++ floating-point assembly type-conversion

所以我搜索了这个主题,发现没有什么真正相关的.

我试着看看这个简单代码背后的程序集:

int main(int argc, char *argv[])
{
    double d = 1.0;
    float f = static_cast<float>(d);

    system("PAUSE");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

这是(使用Visual Studio 2012):

    15:     double d = 1.0;
000000013FD7C16D  movsd       xmm0,mmword ptr [__real@3ff0000000000000 (013FD91AB0h)]  
000000013FD7C175  movsd       mmword ptr [d],xmm0  
    16:     float f = static_cast<float>(d);
000000013FD7C17B  cvtsd2ss    xmm0,mmword ptr [d]  
000000013FD7C181  movss       dword ptr [f],xmm0
Run Code Online (Sandbox Code Playgroud)

我对组装不太满意,但无论如何都试图分析它.所以前两行似乎将双精度值移动3ff0000000000000到寄存器中,然后将寄存器的内容移动到d的内存地址.

然后,我只是不确切知道下一行是什么.该cvtsd2ss操作显然是一个将双精度浮点值转换为单精度浮点值的指令,但我无法找到该指令实际执行的操作.(然后将转换后的值移动到f)的存储空间.

所以我的问题是,这个转换实际上是如何完成的?我知道C++演员会在另一种类型中产生最接近的值,但除此之外,我不知道所执行的实际操作......

Pas*_*uoq 11

cvtsd2ss指令使用FPU的舍入模式进行转换.默认的舍入模式是舍入到最接近的偶数.

为了遵循该算法,有助于记住IEEE 754-1985维基百科页面中的信息,尤其是表示布局的图表.

首先,float计算目标的指数:double类型具有比更宽的范围float,因此对于非常大的结果,结果可以是0.0f(或非正规的),double对于非常大的双重,结果可以是无穷大的.

对于正常情况double转换为法线的常见情况float(大致,当无偏指数double可以用单精度表示的8位表示时),目标有效位数的前23位开始与最重要的原始数字的52位有效数字.

然后有四舍五入的问题:

  • 如果剩下的比特在下面10..0,那么目标有效数字保持原样.

  • 如果剩余位在上面10..0,则目标有效位数递增.如果递增使它溢出(因为它已经是1..1),则进位传播到指数位.由于IEEE 754布局的精心设计,这产生了正确的结果.

  • 如果遗留的位完全正确10..0,那么double正好在两个floats 之间.在这两个选择中,选择具有最后一位0("偶数")的那个.

在此步骤之后,目标有效数对应于float最接近原始的有效数double.

定向舍入模式只是更简单.目标float是非正规的情况稍微复杂一些(必须小心避免"双舍入").

  • @JBL这个答案主要关注double-> float转换,因为它很狡猾.在-DBL_MIN和DBL_MIN(~2*10 ^ -308)之间找到双重非正规.最小的严格正浮点数是~1.401298e-45,因此对于这种特定的转换,任何非正规输入数都不可能在舍入到最接近的情况下舍入到0以外的值. (3认同)
  • 即使是单对双转换也不能只移动位.正常值需要向指数添加896.非正规值需要找到第一个位集,移位有效数,并调整指数. (2认同)