【问题标题】:Is the maximum safe integer representable in IEEE double format 2^53 or 2^54?IEEE 双精度格式 2^53 还是 2^54 可以表示的最大安全整数?
【发布时间】:2022-01-22 06:28:22
【问题描述】:

我在多篇文章中看到,以 IEEE 双精度格式表示的最大安全整数是 2^53https://stackoverflow.com/a/3793950

https://stackoverflow.com/a/1848768

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/MAX_SAFE_INTEGER

但是有一篇帖子说它是2^54https://stackoverflow.com/a/12445693

可以表示所有整数的范围(包括边界) 2^54 作为上限 -2^54 作为下限

这个答案是错误的还是我遗漏了什么?

编辑:

上面的帖子现在似乎更正了。

【问题讨论】:

  • ieee754 double 中可表示的最大整数为DBL_MAX/std::numeric_limits<double>::max()
  • 更正了标题。

标签: floating-point double ieee-754


【解决方案1】:

以 IEEE-754 双精度格式表示的最大安全整数为 2^53 - 1。如果您尝试存储大于此值的值,则它不再安全。虽然可以存储更大的整数,但如果你想确保它保持安全,我建议不要这样做,因为它们会在 2^53 - 1 以上变得不精确。编辑:正如 Eric 的评论所解释的,值本身仍然是精确的,但是在做算术的时候就是四舍五入的时候。

【讨论】:

  • 所以这个答案是错误的?
  • 以什么方式将2^53 存储为double 不安全?
  • 整数值(above 2^53 - 1)不再精确是不安全的。 2^532^53 + 1 是同一件事,因为从那里开始只能表示 整数,它们是 2 的倍数。
  • @Ralf:根据 IEEE-754 标准,所有浮点值都是精确的:每个不是无穷大或 NaN 的浮点数据都精确地表示一个数字。浮点数 2^53 表示 2^53。它不表示 2^53+1,并且 2^53+1 不表示为 2^53 或 IEEE-754 binary64 格式中的任何其他值。我们只是说 2^53+1 没有被表示,或者当转换为 binary64 并舍入到最接近偶数时,结果是 2^53,并不是说 2^53+1 不精确......
  • ... 这很重要:浮点 不近似数字。浮点运算近似实数运算。执行浮点运算时,产生的结果是四舍五入到最接近的可表示值的实数算术结果。这种区别对于分析浮点软件、设计它、调试它以及编写关于它的证明是必不可少的。
【解决方案2】:

但是有一篇帖子说它是 2^54:https://stackoverflow.com/a/12445693

可以表示所有整数的范围(包括边界) 2^54 作为上限 -2^54 作为下限

这个答案是错误的还是我遗漏了什么?

你并没有错过什么。 IEEE 754 双精度二进制浮点 (“double”) 不能表示的第一个整数是 2^53 + 1,它完全在声称的 -2^54..2^54 范围内。这可能是一个错字,因为 -2^53..2^53(包括)范围内的所有整数都可以表示。从 2^53 开始,只能表示 2 的倍数(所以 2^53 + 2 可以,但不能 2^53 + 1)。由于 JavaScript 使用这种形式的双精度,因此很容易看出这一点:

const x = 2**53;
const y = x + 1;
console.log(x.toLocaleString()); // 9,007,199,254,740,992
console.log(y.toLocaleString()); // 9,007,199,254,740,992 -- the same
console.log(x === y);            // true
const z = x + 2;
console.log(z.toLocaleString()); // 9,007,199,254,740,994

对于双精度数,2^53 - 1 是最后一个所谓的“安全”整数,其中“安全”定义为“您可以对其加 1 并获得下一个整数”。 (事实上​​,JavaScript 甚至有一个常量 2^53 - 1:Number.MAX_SAFE_INTEGER。)当你加 1 时,你得到的下一个整数(当然)是 2^53 - 第一个整数,格式不能不再处理每个不同的整数。从 2^53 开始,double 只能按二来计数:2^53, 2^53 + 2, 2^53 + 4, ... 也就是说,此时它只能存储 2 的倍数。(然后之后,它只能按四[4的倍数]计数,然后只能按八[8的倍数]等)

为了完整性:格式可以(准确地)表示很多更大的整数,只是在那个量级上,它不能表示所有,因为格式使用基值(尾数)和指数,当达到 2^53 时,指数只能表示偶数(2 的倍数)。后来指数再次翻转,只能表示 4 的倍数,等等。

让我们想象一下。 IEEE-754 相当复杂,但我们举一个简化的例子(不是 IEEE-754)只是为了解释。假设我们有 4 位存储指数和 8 位存储尾数,假设我们只存储整数。这意味着当指数 = 1 时,我们可以存储 0 到 255 的值:

概念,*不是* IEEE-754! 指数(二进制)尾数(二进制)结果值(十进制) 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 0 0 0 1 0 2 ... 0 0 0 1 1 1 1 1 1 1 1 0 254 0 0 0 1 1 1 1 1 1 1 1 1 255

我们在尾数中达到最大值,因此我们通过使用指数 = 2 并使尾数为 2 的倍数来牺牲范围的精度。现在我们只能以二为单位计数:

概念,*不是* IEEE-754! 指数(二进制)尾数(二进制)结果值(十进制) 0 0 0 2 0 0 0 0 0 0 0 1 2 0 0 0 2 0 0 0 0 0 0 1 0 4 ... 0 0 0 2 0 1 1 1 1 1 1 1 254 0 0 0 2 1 0 0 0 0 0 0 0 256 0 0 0 2 1 0 0 0 0 0 0 1 258 ... 0 0 0 2 1 1 1 1 1 1 1 0 508 0 0 0 2 1 1 1 1 1 1 1 1 510

请注意,我们可以精确地表示值 256,即使它超出尾数可以自己处理的范围 (0-255),因为使用指数我们取尾数值 (128) 并将其加倍得到256. 这正是 2^53 在 double 中发生的情况。但是我们不能表示 257,因为在那个量级上,我们只能处理 2 的倍数。这就是 2^53 + 1 在双精度中发生的情况,我们无法表示它。我们可以表示 2^53 + 2。

【讨论】:

  • 对不起,我以为我很清楚,显然不是,我在标题中添加了 safe 字样。那么那篇文章中的 2^54 是什么?有错吗?
  • @Dan - 啊,没有看到“安全”的添加。那篇文章中的 2^54 是正确的,只是在那个量级上,格式不能再处理一个或两个,从 2^54 开始它只能处理四的倍数,因为双精度的指数部分是 4。
  • 那么最大尺寸是 2^53 还是 2^54?
  • @Dan - 两者都不是。同样,可以用格式表示大得多的整数,只是您不能再表示 围绕它们的整数,因为此时格式不能表示不同的整数。这发生在 2^53。这是它开始计数的第一个值。这就是为什么 2^53 - 1 通常被称为最后一个“安全”整数,它是最后一个指数为 1 的整数。
  • 感谢您提供所有信息,但您不断提出它可以代表更大值的事实,我知道,我只是谈论安全整数。以上所有链接都只讨论安全整数。但其中只有一个说 2^54 是最大 SAFE 整数大小,其余的说是 2^53。那么哪个是正确的,为什么它们不同?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-05-20
  • 2014-05-28
  • 1970-01-01
  • 2011-11-09
  • 1970-01-01
  • 1970-01-01
  • 2013-03-17
相关资源
最近更新 更多