许多早期的答案表明9007199254740992 === 9007199254740992 + 1是真的验证9,007,199,254,740,991是最大且安全的整数。
但是如果我们继续做累加会怎样:
input: 9007199254740992 + 1 output: 9007199254740992 // expected: 9007199254740993
input: 9007199254740992 + 2 output: 9007199254740994 // expected: 9007199254740994
input: 9007199254740992 + 3 output: 9007199254740996 // expected: 9007199254740995
input: 9007199254740992 + 4 output: 9007199254740996 // expected: 9007199254740996
我们可以看到,在大于9,007,199,254,740,992, 只有偶数可代表的.
这是一个解释如何双精度 64 位二进制格式作品。让我们看看如何9,007,199,254,740,992通过使用这种二进制格式来保存(表示)。
使用一个简短的版本来演示它4,503,599,627,370,496:
1 . 0000 ---- 0000 * 2^52 => 1 0000 ---- 0000.
|-- 52 bits --| |exponent part| |-- 52 bits --|
在箭头的左侧,我们有位值 1, 和一个相邻的小数点.通过消耗左侧的指数部分,小数点向右移动 52 步。小数点在末尾结束,我们得到纯二进制的 4503599627370496。
现在让我们继续将小数部分加 1,直到所有位都设置为 1,这等于9,007,199,254,740,991十进制。
1 . 0000 ---- 0000 * 2^52 => 1 0000 ---- 0000.
(+1)
1 . 0000 ---- 0001 * 2^52 => 1 0000 ---- 0001.
(+1)
1 . 0000 ---- 0010 * 2^52 => 1 0000 ---- 0010.
(+1)
.
.
.
1 . 1111 ---- 1111 * 2^52 => 1 1111 ---- 1111.
因为 64 位双精度格式严格分配 52 位给小数部分,如果我们再加 1 就没有更多位可用了,所以我们可以做的是将所有位设置回 0,然后操作指数部分:
┏━━▶ This bit is implicit and persistent.
┃
1 . 1111 ---- 1111 * 2^52 => 1 1111 ---- 1111.
|-- 52 bits --| |-- 52 bits --|
(+1)
1 . 0000 ---- 0000 * 2^52 * 2 => 1 0000 ---- 0000. * 2
|-- 52 bits --| |-- 52 bits --|
(By consuming the 2^52, radix
point has no way to go, but
there is still one 2 left in
exponent part)
=> 1 . 0000 ---- 0000 * 2^53
|-- 52 bits --|
现在我们得到9,007,199,254,740,992,对于大于它的数字,该格式只能处理 2 的增量,因为小数部分的每个增量 1 最终都会乘以指数部分的左边 2。这就是为什么双精度 64 位二进制格式当数字大于时不能容纳奇数9,007,199,254,740,992:
(consume 2^52 to move radix point to the end)
1 . 0000 ---- 0001 * 2^53 => 1 0000 ---- 0001. * 2
|-- 52 bits --| |-- 52 bits --|
按照这种模式,当数字大于 9,007,199,254,740,992 * 2 = 18,014,398,509,481,984 时,只能保留分数的 4 倍:
input: 18014398509481984 + 1 output: 18014398509481984 // expected: 18014398509481985
input: 18014398509481984 + 2 output: 18014398509481984 // expected: 18014398509481986
input: 18014398509481984 + 3 output: 18014398509481984 // expected: 18014398509481987
input: 18014398509481984 + 4 output: 18014398509481988 // expected: 18014398509481988
[之间的数字怎么样?2 251 799 813 685 248,4 503 599 627 370 496)?
1 . 0000 ---- 0001 * 2^51 => 1 0000 ---- 000.1
|-- 52 bits --| |-- 52 bits --|
二进制中的值 0.1 恰好是 2^-1 (=1/2) (=0.5)
所以当数量小于4,503,599,627,370,496(2^52),有一位可用于表示整数的1/2倍:
input: 4503599627370495.5 output: 4503599627370495.5
input: 4503599627370495.75 output: 4503599627370495.5
少于2,251,799,813,685,248(2^51)
input: 2251799813685246.75 output: 2251799813685246.8 // expected: 2251799813685246.75
input: 2251799813685246.25 output: 2251799813685246.2 // expected: 2251799813685246.25
input: 2251799813685246.5 output: 2251799813685246.5
/**
Please note that if you try this yourself and, say, log
these numbers to the console, they will get rounded. JavaScript
rounds if the number of digits exceed 17. The value
is internally held correctly:
*/
input: 2251799813685246.25.toString(2)
output: "111111111111111111111111111111111111111111111111110.01"
input: 2251799813685246.75.toString(2)
output: "111111111111111111111111111111111111111111111111110.11"
input: 2251799813685246.78.toString(2)
output: "111111111111111111111111111111111111111111111111110.11"
可用范围是多少指数部分?格式分配给它的 11 位。
来自Wikipedia(更多详情,去那里)
所以要使指数部分为 2^52,我们确实需要设置 e = 1075。