许多早期的答案显示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。