【问题标题】:How to represent FLOAT number in memory in C如何在 C 中表示内存中的 FLOAT 数
【发布时间】:2011-08-02 09:46:03
【问题描述】:

在阅读教程时,我遇到了如何在内存中表示浮点数。本教程有一个带有浮点数的示例。

   float a=5.2  with below Diagram

谁能告诉上图中这个 5.2 是如何转换成二进制的,以及它是如何在内存中表示的?

【问题讨论】:

标签: c floating-point


【解决方案1】:

如前所述,5.2 表示为符号位、指数和尾数。你如何编码 5.2?

5 很简单:

101. 

其余的,0.2 是 1/5,所以将1.00000...(十六进制)除以 5,得到0.3333333...(十六进制)。

(如果考虑少一位,则更容易遵循:0.FFFF...F / 5 = 3,因此很容易看出0.FFFF... / 5 = 0.33333...。除以时,缺少的一位无关紧要5,所以1.0000... / 5 = 0.3333...也是)。

那应该给你

0.0011001100110011001100110011... 

加5,得到

101.00110011001100110011...         exp 0    (== 5.2 * 2^0)

现在右移(标准化,即确保最高位刚好在小数点之前)并相应地调整指数:

1.010011001100110011001100110011... exp +2   (== 1.3 * 2^2 == 5.2)

现在您只需将 127 的偏差(即129 = 0b10000001)添加到指数并存储它:

0 10000001 1010 0110 0110 0110 0110 0110 

忘记尾数的前1位(它总是应该是1,除了一些特殊值,所以不存储),你得到:

01000000 10100110 01100110 01100110

现在您只需决定小端或大端。

这并不是它的工作原理,但它或多或少是在将 5.2 这样的数字转换为二进制时发生的情况。

【讨论】:

  • 指数计算 2 的幂。这个数字不应该改变它的值,所以如果你将尾数右移一位(相当于除以 2),指数必须增加 1 (相当于乘以 2)。对于 5.2,您执行此操作两次。最高位必须始终为 1,“小数点/二进制点”就在它后面。所以你从 5.2 * 2^0 到 2.6 * 2^1 到 1.3 * 2^2。该值必须始终介于 1 和 2 之间(除了 0 或 非常 小值或 NaN 等特殊值)。这称为标准化。由于最高位始终为 1,因此不存储。
  • 完成了指数的“移位”,因此您可以存储小于零的指数。例如。 0.125 是 1/8。存储为尾数 (1)00...,符号 +,Exp 124 (127-3)
  • 你能解释一下你为什么选择0.FFFFFFF...来划分以及为什么加127?
  • 0.FFFF... 之所以被选中,是因为它仅比 1 低一位且更易于理解。选择 127 是因为这是 IEEE 声明的单精度浮点指数的偏差。添加 127 仅用于存储格式中的值。
  • @Vultrao:确实,零、无穷大、NaN 和非正规是不同的。格式定义明确,但不知道如何从字符串表示形式转换为浮点数。
【解决方案2】:

我认为这个图表不是百分之一正确的。

浮点数按如下方式存储在内存中:

它们被分解成:

  • 签名s(表示是正还是负) - 1 位
  • 尾数m(基本上是您的号码的数字 - 24 位
  • 指数e - 7 位

然后,您可以将任意数字x 写为s * m * 2^e,其中^ 表示取幂。

5.2 应表示如下:

0 10000001 01001100110011001100110    
S    E               M

S=0表示为正数,即s=+1

E 被解释为无符号数,因此代表129。请注意,您必须将E 减去127 才能获得原始指数e = E - 127 = 2

M 必须按以下方式解释:它被解释为以 1 开头的数字,后跟一个点 (.),然后是该点之后的数字。 . 后面的数字是m 中实际编码的数字。我们为每个数字引入权重:

bits in M: 0   1    0     0      1       ... 
weight:    0.5 0.25 0.125 0.0625 0.03125 ... (take the half of the previous in each step)

现在你总结了设置相应位的权重。完成此操作后,添加 1(由于 IEEE 标准中的规范化,您总是添加 1 来解释 M)并获得原始的 m

现在,您计算 x = s * m * 2^e 并获得您的原始号码。

所以,唯一剩下的就是在实际内存中,字节可能是相反的顺序。这就是为什么数字可能不会按如下方式存储的原因:

0 10000001 01001100110011001100110    
S    E               M

但更多的是相反(只需采用 8 位块并镜像它们的顺序)

01100110 01100110 10100110 01000000
MMMMMMMM MMMMMMMM EMMMMMMM SEEEEEEE

【讨论】:

  • IEEE-754 中的浮点数用 8 位指数和 23 位尾数表示。这不包括隐藏位,它始终为 1(除非正规或 NaN 或 0 外),因此尾数(有效位)通常为 24 位,但仅存储 23 位。显示的图表对于小端浮点数几乎是正确的。 M 的最高位应始终为 1,并相应调整指数。
  • FWIW,图表是正确的。它是 little-endian,因此最高字节位于最高地址。
【解决方案3】:

该值在内存中以相反的顺序表示,但令人困惑的地方可能是由于浮点值的准确性损失,5.2f 真正表示为 5.1999998。

【讨论】:

    【解决方案4】:

    用二进制逻辑表示 5.2 很简单:

         8 4 2 1
    5 -> 0 1 0 1
    

    对于十进制数:

    取 .2 并乘以 2(因为它以二进制表示)。

    .2 X 2 = 0.4 -> take the value after the
                    decimal point, don't take the value before
                    the decimal point
    
    .4 X 2 = 0.8
    .8 X 2 = 1.6
    .6 X 2 = 1.2
    .2 X 2 = 0.4
    

    等等……

    在这一步之后,从上述步骤的输出中取小数点前的值:

    .2 X 2 = 0.4 -> take 0 from this for representing in binary form
    

    所以5.2的最终o/p是:

    0101.00110...
    

    【讨论】:

    • 这不是浮点表示,只是普通的二进制表示。
    • @BartlomiejLewandowski OP 询问如何将数字转换为二进制并然后在内存中表示。当然第一步是将其转换为二进制
    【解决方案5】:

    原始浮点数 5.2:

    01000000101001100110011001100110
    ^ sign bit
    

    在内存中,反转字节顺序(如您的图表):

    01100110011001101010011001000000
                            ^ sign bit
    

    【讨论】:

    • 谢谢@Cicada,但我想知道 5.2 的十进制等效值是什么,然后很容易理解它在内存中的表示方式
    【解决方案6】:

    5.2

    数字以“符号位,指数,尾数”的形式存储。 二进制形式的 5 是 8 4 2 1 所以 0101 .2 是

    .2*2=.4   0
    .4*2=.8   0
    .8*2=1.6  1
    

    和符号位 0 因为 Number 是正数。

    0 0101 001....
    

    【讨论】:

      【解决方案7】:

      5.2 二进制 101.00110011...... ------> 非规范化形式 5.2 是 .10100110011.... x 2^3 ------> 显式范式 5.2 是 .0100110011 x 2^3 的隐式范式

      这里符号位变为0(因为数字是正数)和指数 是七位所以它使用了多余的 64 指数符号所以指数 将变为 64+3 = 69 即 1000101 剩下的将是尾数 (总 32 位 - 7 个指数位 - 1 个符号位 = 24 位) 0100 1100 1100 1100 1100 1100

      在上面的例子中符号位是正确的 Excess 64 未应用,因此未归一化,但理想情况下应使用隐式归一化 如果您应用隐式规范化,则第二个字节中的尾数部分将不会出现 MSB '1'。

      【讨论】:

        【解决方案8】:

        5.2表示为“01000000101001100110011001100110”

        查看Converter Applet

        【讨论】:

          【解决方案9】:

          最初发布在其他网站上的转换技术显示出不必要的复杂(尽管它需要我们正确回答)。对于 5.2 在内存中的内存表示:

          首先将其转换成简单的二进制系统,得到101.001100110011001100110011

          现在将其更改为科学形式:1.01001100110011001100110011 x 10^2。

          现在我们的符号位是 0,因为数字是正数

          对于指数,我们需要 (127 + 2) 最多 8 位,这给了我们 10000001

          分数是 01001100110011001100110 。 (23位)(舍弃科学形式的前1)

          => 表示是

          0 10000001 0100 1100 1100 1100 1100 110

          【讨论】:

            【解决方案10】:

            以下两个参考资料确实帮助我理解了二进制格式的 IEE 754 浮点数编码,

            http://www.pitt.edu/~juy9/142/slides/L3-FP_Representation.pdf

            http://en.wikipedia.org/wiki/Single-precision_floating-point_format

            【讨论】:

            • 感谢参与,但这个问题已经存在三年了,已经回答了。另外,请注意,此站点上未充分考虑仅链接的答案,因为链接过时并且指向大型完整文档的链接使读者无法弄清楚文档如何回答问题。最佳答案提供链接,但在问题的特定上下文中提供解释。
            【解决方案11】:
            int a;
            float b=5.2;
            memcpy(&a, &b, 4);
            printf("%d",a);
            

            这给出 0100 0000 1010 0110 0110 0110 1000 0001 (1084647041)

            【讨论】:

              猜你喜欢
              • 2011-12-12
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-10-21
              • 2015-07-19
              相关资源
              最近更新 更多