我在处理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
)?
答案 0 :(得分:10)
这个数字确实是一个双倍。尾数有52位(source and extra information on doubles)。因此,从一位存储2 ^ 53个印章。
使用3个符号位(相当直接)和另外两个部分(尾数M和指数E)存储该数字。该数字计算如下:
(1 + M / 2 ^ 53)* 2 ^(E-1023)
我可能会有一些细节,但基本的想法是存在的。因此,当数字为2 ^ 53时,2 ^(E-1023)= 2 ^ 53且由于M中只有52位,因此您不能再代表最低位。
答案 1 :(得分:5)
@CrazyCasta给出的答案很好。
唯一要补充的是你的第二个问题:
如果
2^53
是实际最大值,那么为什么我们有Number.MAX_VALUE
(1.7976931348623157e+308
)?
如您所示,可以存储大于2^53
的数字,但精度低于2^0
。随着数字越来越大,它们失去了越来越多的精确度。
因此Number.MAX_VALUE
中的最大值表示它可以表示的“最大”值;但这并不意味着准确度与2^1
或2^53
附近的值相同。
这是一个必然结果,Number.MIN_VALUE
是Number可以包含的最小值;不是最负面的。也就是说,它是最接近零的非零数字:5.00E-324
(注意这是一个正数!)。
答案 2 :(得分:2)
long中可存储的最大值远远大于可存储的的精确度的最大值。浮点数具有固定的最大有效位数,但数字的大小可以变得更大。
为指数分配了一定数量的比特(2的幂),并且隐含地乘以存储在其余比特中的尾数。超过某一点,你会失去精确度,但你可以继续增加指数来表示更大和更大的数量。