【问题标题】:Convert int to float: how it is done将 int 转换为 float:它是如何完成的
【发布时间】:2012-07-19 21:25:59
【问题描述】:

我是 C 编程语言的新手,我想问一个问题。

这里的整数 i 被转换为浮点数,然后 f(不知何故)成功代表 5.0:

int i = 5;
float f = i;   //Something happened here...

但是,如果我们尝试这种方法:

int i = 5;
float f = *(float *)&i;

f 不会得到 5.0,因为它以“浮点方式”解释存储在 i 中的位。那么编译器在第一种情况下实际上做了什么魔法呢?这似乎是一项相当费力的工作......有人可以指定吗?谢谢。

【问题讨论】:

    标签: c++ c casting type-conversion


    【解决方案1】:

    这是一项费力的工作,但任何支持浮点的 CPU 都会提供执行此操作的指令。

    如果您必须自己将 2 的补码 int 转换为 IEEE 浮点格式,您会:

    • 取整数 base-2 对数(与最高设置位的索引密切相关),它为您提供指数。对此进行偏移并将其存储在浮点数的指数位中。
    • 将int 的顶部n 位(从第一个设置的无符号位之后 位开始)复制到浮点数的有效数字中。 nfloat 中的许多有效位(对于 32 位单精度浮点数为 23)。如果int 中有任何剩余位(即大于 224),并且您有空间的位之后的下一位是1,您可能会或可能会不根据操作中的 IEEE 舍入模式进行舍入。
    • 将符号位从int 复制到float

    【讨论】:

    • 尾数没问题,需要补充的是指数需要计算
    【解决方案2】:

    如果你看一下程序集

        int i = 5;
    000D139E  mov         dword ptr [i],5  
        float f = i;
    000D13A5  fild        dword ptr [i]  
    000D13A8  fstp        dword ptr [f]  
    

    fild有什么魔力

    【讨论】:

    • 它务实地回答了what magic the complier actually does 的问题,并带有一个很好的链接,+1。
    【解决方案3】:

    将 int 位转换为浮点数

    float IntBitsToFloat(long long int bits)
    {
        int sign     = ((bits & 0x80000000) == 0) ? 1 : -1;
        int exponent = ((bits & 0x7f800000) >> 23);
        int mantissa =  (bits & 0x007fffff);
    
        mantissa |= 0x00800000;
       // Calculate the result:
       float f = (float)(sign * mantissa * Power(2, exponent-150));
       return f;
    }
    

    【讨论】:

      【解决方案4】:

      在 IA32 系统上,编译器会生成以下内容:-

      fild dword ptr [i] ; load integer in FPU register, I believe all 32bit integers can be represented exactly in an FPU register
      fstp dword ptr [f] ; store fpu register to RAM, truncating/rounding to 32 bits, so the value may not be the same as i
      

      【讨论】:

        【解决方案5】:

        魔法取决于您的平台。

        一种可能性是您的 CPU 有一条特殊指令可以将浮点数复制到整数寄存器中。

        当然,必须有人设计这些 CPU,所以这并不是对手头算法的真正解释。

        一个平台可能正在使用这样的浮点格式(实际上,这是一个定点格式):

        [sIIIIFFFF]
        

        s 是符号,Is 是点之前的部分,Fs 是点之后的部分,例如(点是虚拟的,仅用于演示)

         -  47.5000
        [sIIII.FFFF]
        

        在这种情况下,转换几乎是微不足道的,可以使用位移来实现:

            -47.5000
         >> 4
         ---------------
            -47
        

        和本例一样,商品 C++ 实现使用浮点表示,通常称为IEEE Floating Point,另请参见IEEE 754-1985。这些比定点数更复杂,因为它们实际上指定了一个简单的公式,形式为 _s*mn,但是,它们具有明确定义的解释,您可以将它们展开成更合适的东西。

        【讨论】:

          【解决方案6】:

          嗯,我刚刚在VC++下编译了有问题的代码,看了下反汇编:

             int i = 5;
          00A613BE  mov         dword ptr [i],5 
          
             float f = i;
          00A613C5  fild        dword ptr [i] 
          00A613C8  fstp        dword ptr [f] 
          

          第一个汇编语句将 5 移动到由 i 表示的内存中。第二条语句 fild 将 i 表示的内存转换为浮点数,并将其压入 FPU 堆栈。第三条语句 fstp 获取 FPU 堆栈上的内存并将其移至 f。

          【讨论】:

          • 稍微解释一下如何?提及这段代码的作用,我保证至少有一个赞成票:)
          • 第一个汇编语句将 5 移动到 i 表示的内存中。第二条语句 fild 将 i 表示的内存转换为浮点数,并将其压入 FPU 堆栈。第三条语句 fstp 获取 FPU 堆栈上的内存并将其移至 f。
          • +1 表示评论,但是如何将此信息添加到您的答案中?
          【解决方案7】:

          在几乎所有现代系统中,浮点运算的规范都是 IEEE754 标准。这详细说明了从内存中的布局到如何传播截断和舍入的所有内容。这是一个很大的领域,在科学和工程编程中您经常需要详细考虑。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2011-11-02
            • 1970-01-01
            • 2016-08-19
            • 1970-01-01
            • 2012-05-05
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多