代码之家  ›  专栏  ›  技术社区  ›  Yatendra Rathore

浮点数是如何存储在CPU中的?

  •  4
  • Yatendra Rathore  · 技术社区  · 8 年前

    浮点的指数是一个8位字段。允许大数字或 消极的实际指数是8位字段的值减去127。 127是32位浮点数的“指数偏差”。 浮点的分数域有一个小惊喜。因为定义了0.0 指数场等于127,分数场设置为所有O。所有其他 数字至少有一个1位,因此IEEE 754格式使用隐式1 被解释为1.00000000000000000。这允许分数 字段有效为24位。这是一个由

    你能解释一下它们是如何存储在内存中的吗?我不需要参考资料,我只需要一个好的解释,这样我就可以很容易地理解。

    2 回复  |  直到 8 年前
        1
  •  8
  •   Peter Cordes    5 年前

    浮点数跟在后面 the IEEE754 standard 。他们一直在使用这组规则,主要是因为浮点数可以(相对)轻松地与整数和其他浮点数进行比较。

    浮点有两种常见版本:32位( IEEE binary32 aka single-precision float )和64位( binary64 aka double precision

    • 指数:32位8位,64位11位

    还有一个额外的位,符号位,指定所考虑的数字是正还是负。

    现在,举个例子 12,375 基数10(32位):

    • 第一步是将此数字转换为基数2: 1100.011

    • 接下来,你必须移动“逗号”,直到你得到 1.100011 (直到 . 是1)。我们移动逗号多少次?3,这是指数。这意味着我们的数字可以表示为 1.100011*2^3

      移动 . 1. 被称为“正常化”。一个太小而无法用这种方式表示的数(指数的有限范围)称为次正规数或非正规数。

    • 之后,我们必须将偏差添加到指数中。对于32位浮点中的8位指数字段,这是127。我们为什么要这样做?答案是:因为这样我们可以更容易地比较浮点和整数。(将FP位模式作为整数进行比较,如果它们具有相同的符号,则告诉您哪个具有较大的幅度。)此外,增加位模式(包括从尾数到指数的进位)会将幅度增加到下一个可表示的值。( nextafter() )

      如果我们不这样做,负指数将使用两个补码表示法表示,基本上在最重要的位放一个1。但通过这种方式,较小的浮点似乎大于正指数浮点。因此:我们只需加127,用这个小“技巧”所有正指数从 10000000 01111110 基数2(即-1基数10)。

    在我们的示例中,归一化指数为 10000010 基数2。

    • 最后一件事是添加mantix( .100011

      01000001010001100000000000000000
       |  exp ||      mantix         |
      

    (第一位是符号位)

    有一个很好的在线转换器,它可以可视化32位浮点的位,并显示它所代表的十进制数。您可以修改其中一个,它会更新另一个。 https://www.h-schmidt.net/FloatConverter/IEEE754.html


    • 非数字NaN(有偏指数=所有1;尾数!=0)
    • 对于次正态数也没有说太多(有偏指数=0意味着尾数中的前导0,而不是正态1)。

    还有其他IEEE-754格式,如16位半精度,一个值得注意的扩展精度格式是80位x87,它显式存储有效位的前导1,而不是由零或非零指数暗示。

    IEEE-754甚至定义了一些十进制浮点格式,使用10^exp精确表示十进制分数而不是二进制分数。(硬件对这些的支持有限,但确实存在)。

        2
  •  1
  •   old_timer    8 年前

    然后在小学的某个时候,在做了一段时间的分数之后,我们学习了小数点。这只是我们放在两个数字之间的一个周期,它表示最后一个整数在哪里,分数从哪里开始。我可以停下来说,没有任何理由让基数2和基数10,从基数13到基数27不同,你只要在两个数字之间加一个句点,以指示最后一个整数和分数的第一部分在哪里。但浮点运算更进一步。这可能是在小学或中学后期,但他们最终教会了我们科学记数法和/或其他通过移动小数点来表示数字的方法,这种小数仍然表示最后一个整数和分数开头之间的边界,但在另一边,我们对基数乘以幂

    12345.67 = 1.234567 * 10^4
    

    这就是谜题的剩余部分。用铅笔和纸,只要我们有足够的纸和足够的铅笔芯(石墨),我们就可以用任意多的数字来写数字,但正如你们已经知道的那样,对于整数,我们通常受到寄存器大小的限制,现在,我们可以使用其他小学知识将8位alu转换为无限多的位alu(只要我们有足够的内存/存储位),但在这种情况下,我们仍在一次处理8位的事情。在这种情况下,他们最初选择了32位、64位和80位(或者可能是后来的)格式,因此我们的位受到这些数字的严格限制(我们现在有16位,可能更小,尽管这没有多大意义),他们使用幂指数的某物时间基。某物是上面1.234567的尾数,但存储时没有小数点1234567。小数点的位置是假设/约定的(已知的)。它是数字中的第一个非零数字,因此123456.7我们将其移动到1.234567,并将指数调整为78.45。我们将其移动到7.845,并调整基本乘法器上的指数。因为这是二进制的,所以只有一个值不是零,即1(一个位是0或1),所以011101.000我们将其移动到1.110100并调整指数。(这类似于科学记数法,但以2为基数)

    接下来,这个尾数中的位数或科学记数法中的有效位数如果你想这样想的话,它被限制在formst 23或一些位数内,请参阅单精度浮点格式的维基百科页面(32位一,双精度是64位,其工作方式完全相同,只是有更多的尾数和指数位)。所以我们取数字,不管它有多少位,我们找到最重要的一位,我们把小数点移到那里,然后调整乘法器上的表达式,就像我们上面做的那样

    11101.01 = 1.110101 * 2^4
    

    从技术上讲,我们不需要在小数点之前存储1,也不需要存储2,但我们需要存储110101,我们需要以二进制形式存储4。除了上面例子中表示正的符号,所以符号、指数和尾数,我们可以重构这个数。或者任何符合那些不太小或不太大的数(例如指数不适合分配的位数)。

    我还说了一些特殊情况,到目前为止,我们有一位符号是正或负,8位是2乘法器幂的编码指数,我们有数字中有效数字的尾数或分数位。但是关于零呢?零中没有非零位,我们如何表示这个数字?这是一个特例,几乎是硬编码的数字,但实际上可以用不同的位模式来表示+0和-0,但规范的更高版本我认为鼓励或规定,结果为零的数学是正的,但我不知道,我肯定很多年没有看到过规范的副本,因为你必须付费才能合法获得它。其他特殊情况称为nan或不是数字,它们也是表示nan的特殊位模式……有不止一个nan,你可以在尾数中放入不同的模式。例如,当你除以零,或者当你的数字太大,以至于你不能用2的幂N来表示它,因为N对于指数中编码的位数来说太大(在单精度编码之前大于+128),或者数字太小(指数小于-127)。虽然在某些格式中有称为微小数字或非规范化的数字,并且这些数字不是1.xxxx,但它们忽略了这一点,并且有0.000…1xxxx,这是一种无效的格式,但只比我们可以表示的最小数字小一点点,一些FPU/软件不支持非规范化。

    现在去维基百科搜索单精度浮点格式,现在这个页面应该很有意义了……我希望。。。