81

我对浮点数的表示方式略知一二,但恐怕还不够。

一般的问题是:

对于给定的精度(出于我的目的,以 10 为基数的精确小数位数),对于 16、32 和 64 位 IEEE-754 系统可以表示什么范围的数字?

具体来说,我只对精确到 +/-0.5(个位)或 +/-0.0005(千分位)的 16 位和 32 位数字的范围感兴趣。

4

7 回答 7

112

对于给定的IEEE-754浮点数X,如果

2^E <= abs(X) < 2^(E+1)

那么从X到下一个最大的可表示浮点数(epsilon)的距离是:

epsilon = 2^(E-52)    % For a 64-bit float (double precision)
epsilon = 2^(E-23)    % For a 32-bit float (single precision)
epsilon = 2^(E-10)    % For a 16-bit float (half precision)

上述等式允许我们计算以下内容:

  • 对于半精度...

    如果您希望精度为 +/-0.5(或 2^-1),则该数字的最大大小为 2^10。任何大于此的浮点数之间的距离大于 0.5。

    如果您希望精度为 +/-0.0005(约 2^-11),则该数字的最大大小为 1。任何大于此的数字且浮点数之间的距离大于 0.0005。

  • 对于单精度...

    如果您希望精度为 +/-0.5(或 2^-1),则该数字的最大大小为 2^23。任何大于此的浮点数之间的距离大于 0.5。

    如果您希望精度为 +/-0.0005(约 2^-11),则该数字的最大大小为 2^13。任何大于此值且浮点数之间的距离大于 0.0005。

  • 对于双精度...

    如果您希望精度为 +/-0.5(或 2^-1),则该数字的最大大小为 2^52。任何大于此的浮点数之间的距离大于 0.5。

    如果您希望精度为 +/-0.0005(约 2^-11),则该数字的最大大小为 2^42。任何大于此值且浮点数之间的距离大于 0.0005。

于 2009-05-16T16:30:44.070 回答
22

对于浮点整数(我将根据 IEEE 双精度给出我的答案),1 到 2^53 之间的每个整数都是可以精确表示的。超过 2^53 时,可精确表示的整数之间的间距为 2 的递增幂。例如:

  • 2^53 + 2 和 2^54 之间的每个第二个整数都可以精确表示。
  • 可以精确表示 2^54 + 4 和 2^55 之间的每第四个整数。
  • 可以精确表示 2^55 + 8 和 2^56 之间的每第 8 个整数。
  • 可以精确表示 2^56 + 16 和 2^57 之间的每 16 个整数。
  • 可以精确表示 2^57 + 32 和 2^58 之间的每个第 32 个整数。
  • 可以精确表示 2^58 + 64 和 2^59 之间的每 64 个整数。
  • 可以精确表示 2^59 + 128 和 2^60 之间的每 128 个整数。
  • 可以精确表示 2^60 + 256 和 2^61 之间的每 256 个整数。
  • 可以精确表示 2^61 + 512 和 2^62 之间的每 512 个整数。. . .

不能精确表示的整数会四舍五入到最接近的可表示整数,因此最坏情况的舍入是可表示整数之间间距的 ​​1/2。

于 2009-05-16T21:30:50.403 回答
19

精确引用来自 Peter R 的 MSDN 参考链接可能是一个很好的经验法则,但当然现实更复杂。

“浮点”中的“点”是二进制点而不是小数点这一事实有悖于我们的直觉。经典的例子是 0.1,它只需要十进制的一位精度,但根本不能精确地用二进制表示。

如果您有一个周末要打发,请查看每个计算机科学家应该了解的关于浮点运算的知识。您可能会对PrecisionBinary to Decimal Conversion部分特别感兴趣。

于 2009-05-16T16:15:05.293 回答
5

首先,IEEE-754-2008 和 -1985 都没有 16 位浮点数;但它是一个 5 位指数和 10 位小数的建议加法。IEE-754 使用专用的符号位,所以正负范围是一样的。此外,分数前面有一个隐含的 1,所以你会得到一个额外的位。

如果你想要精确到个位,就像你可以表示每个整数一样,答案很简单:指数将小数点移动到分数的右端。所以,一个 10 位的分数可以得到 ±2 11

如果你想要小数点后的一位,你放弃它之前的一位,所以你有 ±2 10

单精度有一个 23 位小数,所以你有 ±2 24 个整数。

小数点后需要多少位精度完全取决于您正在执行的计算,以及您正在执行多少位。

  • 2 10 = 1,024
  • 2 11 = 2,048
  • 2 23 = 8,388,608
  • 2 24 = 16,777,216
  • 2 53 = 9,007,199,254,740,992(双精度)
  • 2 113 = 10,384,593,717,069,655,257,060,992,658,440,192(四精度)

也可以看看

于 2009-05-16T16:14:09.993 回答
2

参见IEEE 754-1985

v = (-1)^sign * s^(exponent-exponent_bias) * (1 + 分数)

注意(1 + 分数)。正如@bendin指出的那样,使用二进制浮点,您不能表示简单的十进制值,例如 0.1。这意味着您可以通过多次执行简单的加法或调用截断之类的方法来引入舍入误差。如果您对任何类型的精度感兴趣,实现它的唯一方法是使用定点小数,它基本上是一个缩放整数。

于 2009-05-16T16:48:17.227 回答
0

如果我正确理解您的问题,这取决于您的语言。
对于 C#,请查看MSDN 参考。Float 具有 7 位精度和双 15-16 位精度。

于 2009-05-16T15:36:33.467 回答
0

我花了很长时间才弄清楚,在 Java 中使用双精度时,我并没有在计算中失去显着的精度。浮点实际上具有以相当合理的精度表示数字的非常好的能力。我失去的精度是在将用户输入的十进制数字转换为本机支持的二进制浮点表示时立即丢失的。我最近开始将我所有的数字转换为 BigDecimal。BigDecimal 在代码中处理的工作比浮点数或双精度数要多得多,因为它不是原始类型之一。但另一方面,我将能够准确地表示用户输入的数字。

于 2009-05-16T17:41:07.070 回答