任何人都可以详细说明 JavaScript 中的数字精度和溢出吗?

Can anyone please elaborate Number precision and overflow in JavaScript?

我正在 MDN 上查看 Number.isInteger()。我遇到了这个例子 -

Number.isInteger(5.000000000000001); // false

我把值改成5.0000000000000001,如果我在控制台执行同样的方法,结果是:

Number.isInteger(5.0000000000000001); // true

还有5.0000000000000001 === 5结果是true.

有人可以解释一下这里发生了什么吗?

JavaScript 使用 IEEE-754 基本 64 位二进制 floating-point 格式。在这种格式中,每个有限数都表示为整数 M 乘以 2 的幂,2E. M的量级必须小于253,而E可能在-1074到971之间.(更常见的描述比例 ME 不同,因此 M 有小数位而不是是一个整数,但这在数学上是等价的。)

对于数字5.000000000000001,最精确的表示是用E = −50,因为这使得M为大到合适,大约 5•250 = 1.25•252。如果我们将 E 缩小一倍,那么 M 将不得不约为 1.25•253,这超过253 限制。

因此,给定 E = −50,我们需要 5.000000000000001 = M•2−50,这意味着 M = 5.000000000000001•250 = 5•250 + .000000000000001• 250。显然第一项 5•250 是一个整数。第二项 .000000000000001•250 约为 1.1259。所以,在把5.000000000000001转成JavaScript的Number格式时,需要把M做成整数,所以要将1.1259四舍五入为1,结果是M = 5•250 + 1,所以数为(5•250 + 1)•2−50 = 5.00000000000000088817841970012523233890533447265625.

另一方面,当我们有 5.0000000000000001,再加上一个零,我们有 5.0000000000000001•250 = 5•250 + .0000000000000001•250。在这种情况下,第二项 .0000000000000001•250 约为 .11259。所以,当把5.0000000000000001转成JavaScript的Number格式时,我们要将.11259四舍五入为0,所以这个数是((5•250)•2−50 = 5.