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

时间:2013-05-24 14:40:35

标签: c++ assembly floating-point type-conversion

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

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

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

    system("PAUSE");
    return 0;
}

(使用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

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

然后,我只是不确切知道下一行是什么。 cvtsd2ss操作显然是convert double precision floating point value to single precision floating point value的指令,但我无法找到该指令实际执行的操作。 (然后将转换后的值移动到f)的存储空间。

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

1 个答案:

答案 0 :(得分:11)

cvtsd2ss指令使用FPU的舍入模式进行转换。默认的舍入模式是round-to-nearest-even。

为了遵循算法,有助于记住IEEE 754-1985 Wikipedia page处的信息,尤其是代表布局的图表。

首先,计算目标float的指数:double类型的范围大于float,因此结果可能是0.0f(或非正规)对于非常小的double,或非常大的双倍的无限值。

对于正常double被转换为正常float的通常情况(大致,当double的无偏指数可以用单个的8位表示时 - 精度表示),目标有效位数的前23位开始与原始数字的52位有效位数的最高有效位相同。

然后存在四舍五入的问题:

  • 如果剩余位低于10..0,则目标有效位将保持原样。

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

  • 如果遗留的位完全是10..0,则double恰好位于两个float之间。在这两个选项中,选择最后一位0(“偶数”)的选项。

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

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