6

我在处理 JavaScript 数字时发现了以下奇怪的行为。

var baseNum = Math.pow(2, 53);
console.log(baseNum); //prints 9007199254740992

console.log(baseNum + 1); //prints 9007199254740992 again!

console.log(baseNum + 2); //prints 9007199254740994, 2 more than +1

console.log(baseNum + 3) // prints 9007199254740996, 2 more than +2
console.log(baseNum + 4) // prints 9007199254740996, same as +3

这里发生了什么?我知道 JavaScript 只能表示数字2^53(它们在内部是“双”?),但为什么会出现这种行为?

如果2^53是实际最大值,那么为什么我们有Number.MAX_VALUE( 1.7976931348623157e+308)?

4

3 回答 3

10

这个数字真的是双倍的。尾数有 52 位(双精度源和额外信息)。因此,存储 2^53 会砍掉一位。

该数字使用 3 个符号位(相当直截了当)和另外两个部分存储,尾数 M 和指数 E。该数字计算如下:

(1 + M/2^53) * 2^(E-1023)

我可能有一些细节有点偏离,但基本的想法就在那里。因此当数字为 2^53 时,2^(E-1023) = 2^53 并且由于 M 中只有 52 位,因此您不能再表示最低位。

于 2012-09-26T05:46:03.813 回答
5

@CrazyCasta给出的答案很好。

唯一要添加的是您的第二个问题:

如果2^53是实际最大值,那么为什么我们有Number.MAX_VALUE( 1.7976931348623157e+308)?

正如您所展示的,它可以存储大于 的数字2^53,但精度低于2^0。随着数字变得越来越大,它们失去了越来越多的精度。

因此,最大值Number.MAX_VALUE表示它可以表示的“最大”值;但这并不意味着准确度与2^1or附近的值相同2^53

一个推论是Number 可以包含Number.MIN_VALUE最小值;不是最消极的。也就是说,它是最接近零的非零数:(5.00E-324注意这是一个正数!)。

于 2012-09-26T05:52:13.483 回答
2

long 中可存储的最大值远大于 long 中可精确存储的最大值。浮点数具有固定的最大有效位数,但数字的大小可以变得更大。

为指数(2 的幂)分配了一定数量的位,并且隐式乘以存储在其余位中的尾数。超过某个点,您会失去精度,但您可以继续增加指数以表示越来越大的量级。

于 2012-09-26T05:50:38.117 回答