使用Bitwise将Int转换为Float/Float到Int

And*_*w T 10 floating-point assembly arm bit-manipulation ieee-754

我想知道你是否可以帮助解释将整数转换为float或float转换为整数的过程.对于我的课程,我们只使用按位运算符来完成此操作,但我认为从类型到类型的强制理解将在这个阶段帮助我更多.

根据我目前所知,对于int要浮动,你必须将整数转换为二进制,通过查找有效数,指数和分数来规范化整数的值,然后从那里输出浮点值?

至于float到int,你必须将值分成有效数,指数和分数,然后反转上面的指令得到一个int值?

我试着按照这个问题的说明:在C中将float转换为int(按位)

但我真的不能理解它.

另外,有人可以解释为什么在将int转换为float时大于23位的值需要舍入?

提前致谢

Joe*_*e Z 17

首先,如果你想更好地理解浮点弱点,你应该考虑阅读一篇论文:"每个计算机科学家应该知道的关于浮点运算的知识",http://www.validlab.com/goldberg/paper.pdf

现在来一些肉.

以下代码是简单的,并尝试从unsigned int0 <值<2 24的范围内生成IEEE-754单精度浮点数.这是您在现代硬件上最可能遇到的格式,它是您在原始问题中引用的格式.

IEEE-754单精度浮点数分为三个字段:单符号位,8位指数和23位有效数(有时称为尾数).IEEE-754使用隐藏的1有效数,意味着有效数实际上是24位.这些位从左到右打包,符号位在第31位,指数在第30位...... 23位,有效位在位22 .. 0中.来自维基百科的下图说明:

浮点格式

指数的偏差为127,这意味着与浮点数关联的实际指数比指数字段中存储的值小127.因此,指数0将被编码为127.

(注意:完整的维基百科文章可能对您有意思.参考:http://en.wikipedia.org/wiki/Single_precision_floating-point_format)

因此,IEEE-754号0x40000000解释如下:

  • 位31 = 0:正值
  • 位30 .. 23 = 0x80:指数= 128 - 127 = 1(又称2 1)
  • 位22..0都是0:有效值= 1.00000000_00000000_0000000.(注意我恢复了隐藏的1).

所以值是1.0 x 2 1 = 2.0.

要将unsigned int上面给出的有限范围内的转换为IEEE-754格式的某些内容,您可以使用类似下面的函数.它采取以下步骤:

  • 将整数的前导1 与浮点表示中隐藏 1 的位置对齐.
  • 在对齐整数时,记录所做的轮班总数.
  • 掩盖隐藏的1.
  • 使用所做的班次数,计算指数并将其附加到数字.
  • 使用reinterpret_cast,将得到的位模式转换为a float.这部分是一个丑陋的黑客,因为它使用类型惩罚指针.你也可以通过滥用来做到这一点union.一些平台提供内在操作(例如_itof)以使这种重新解释不那么难看.

有更快的方法可以做到这一点; 如果不是超级有效的话,这个是教学上有用的:

float uint_to_float(unsigned int significand)
{
    // Only support 0 < significand < 1 << 24.
    if (significand == 0 || significand >= 1 << 24)
        return -1.0;  // or abort(); or whatever you'd like here.

    int shifts = 0;

    //  Align the leading 1 of the significand to the hidden-1 
    //  position.  Count the number of shifts required.
    while ((significand & (1 << 23)) == 0)
    {
        significand <<= 1;
        shifts++;
    }

    //  The number 1.0 has an exponent of 0, and would need to be
    //  shifted left 23 times.  The number 2.0, however, has an
    //  exponent of 1 and needs to be shifted left only 22 times.
    //  Therefore, the exponent should be (23 - shifts).  IEEE-754
    //  format requires a bias of 127, though, so the exponent field
    //  is given by the following expression:
    unsigned int exponent = 127 + 23 - shifts;

    //  Now merge significand and exponent.  Be sure to strip away
    //  the hidden 1 in the significand.
    unsigned int merged = (exponent << 23) | (significand & 0x7FFFFF);


    //  Reinterpret as a float and return.  This is an evil hack.
    return *reinterpret_cast< float* >( &merged );
}
Run Code Online (Sandbox Code Playgroud)

您可以使用检测数字中前导1的函数来提高此过程的效率.(这些有时会出现clz"计数前导零"或norm"标准化"等名称.)

您还可以通过记录符号,取整数的绝对值,执行上述步骤,然后将符号放入数字的第31位,将其扩展为带符号的数字.

对于整数> = 2 24,整个整数不适合32位浮点格式的有效数字段.这就是你需要"舍入"的原因:你失去了LSB以使价值合适.因此,多个整数将最终映射到相同的浮点模式.确切的映射取决于舍入模式(向-Inf舍入,向+ Inf舍入,向零舍入,向最近偶数舍入).但事实是你不能将24位推到少于24位而没有一些损失.

您可以根据上面的代码看到这一点.它的工作原理是将前导1对齐到隐藏的1位置.如果值> = 2 24,则代码需要向右移动,而不是向左移动,这必然会使LSB移位.舍入模式只是告诉您如何处理移位的位.