c++ - 十进制到IEEE单精度 float

标签 c++ assembly floating-point int single-precision

我对学习如何仅使用按位运算符将整数值转换为IEEE单精度浮点格式感兴趣。但是,对于要知道在计算指数时需要多少逻辑左移该怎么办,我感到困惑。

给定一个整数,例如15,我们有:

二进制:1111

-> 1.111 x 2 ^ 3 =>在第一位后放置一个小数点后,我们发现'e'值为3。

E = Exp-偏差
因此,Exp = 130 = 10000010

而有效位数将是:111000000000000000000000

但是,我知道'e'的值为3,因为我能够看到在将小数点放在第一位之后有三位。在一般情况下,是否有更通用的编码方法?

同样,这是一个int到float转换,假设整数是非负,非零且不大于尾数允许的最大空间。

另外,有人可以解释为什么大于23位的值需要舍入吗?
提前致谢!

最佳答案

首先,如果您想更好地理解浮点数,则应该考虑阅读以下文章:“每个计算机科学家应该了解的浮点算术知识” http://www.validlab.com/goldberg/paper.pdf

现在要一些肉。

下面的代码是基本内容,并尝试从unsigned int生成范围为0
IEEE-754单精度浮点数分为三个字段:单符号位,8位指数和23位有效数(有时称为尾数)。 IEEE-754使用隐藏的1有效数字,这意味着有效数字实际上总共为24位。这些位从左到右打包,符号位在位31中,指数在位30..23中,有效数在位22..0中。维基百科的下图说明:

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

(注意:完整的Wikipedia文章可能对您来说很有趣。引用:http://en.wikipedia.org/wiki/Single_precision_floating-point_format)

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

  • 位31 = 0:正值
  • 位30 .. 23 = 0x80:指数= 128-127 = 1(又名21)
  • 位22 .. 0均为0:有效位数= 1.00000000_00000000_0000000。 (请注意,我恢复了隐藏的1)。

  • 因此,值为1.0 x 21 = 2.0。

    要将上面给出的有限范围内的unsigned int转换为IEEE-754格式的某种内容,您可以使用下面的函数。它采取以下步骤:
  • 将整数的前导1与浮点表示形式中隐藏1的位置对齐。
  • 对齐整数时,记录进行的总移位数。
  • 掩盖隐藏的1.
  • 使用进行的移位次数,计算指数并将其附加到该数字上。
  • 使用reinterpret_cast将生成的位模式转换为float。这部分很丑陋,因为它使用了类型标记指针。您也可以通过滥用union来做到这一点。某些平台提供了内部操作(例如_itof),以使这种重新解释不太难看。

  • 有更快的方法可以做到这一点。如果不是 super 有效的话,这在教学上是有用的:
    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 );
    }
    

    您可以使用检测数字前1的功能使此过程更有效。 (这些名称有时用clz表示“计数前导零”,或用norm表示“规范化”。)

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

    对于> = 224的整数,整个整数不适合32位浮点格式的有效数字段。这就是为什么您需要“四舍五入”的原因:为了使值合适,您丢失了LSB。因此,多个整数最终将映射到相同的浮点模式。确切的映射取决于舍入模式(朝-Inf舍入,朝+ Inf舍入,朝零舍入,朝最近的偶数舍入)。但是事实是,您不能将24位减少到少于24位而不会造成任何损失。

    您可以通过上面的代码看到这一点。通过将前导1对齐到隐藏的1位置来工作。如果值> = 224,则代码​​将需要向右移动而不是向左移动,并且这必然会将LSB移开。舍入模式仅告诉您如何处理移位的位。

    关于c++ - 十进制到IEEE单精度 float ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20307276/

    相关文章:

    assembly GDB 在 GUI 表之间切换

    Java减去 float 是无穷大?

    SIG_ERR 上的 C++ 旧式转换警告

    c++ - 在集合中查找结构 vector

    c++ - 什么是 undefined reference /未解析的外部符号错误,我该如何解决?

    gcc - 在GCC内联汇编中包装CMPXCHG8B的正确方法(32位)

    c++ - 为什么当编译器从 C++ 代码创建完全相同类型的指令时,此代码无法编译

    c++ - 可识别 C++ 的 Diff 实用程序

    c++ - 浮点 == 可以吗?

    python - Python 中二进制的浮点表示(位非十六进制)