提问人:TALlama 提问时间:11/21/2008 最后编辑:Peter MortensenTALlama 更新时间:3/2/2022 访问量:661593
一个数字可以在不损失精度的情况下达到 JavaScript 的最高整数值是多少?
What is JavaScript's highest integer value that a number can go to without losing precision?
答:
>= ES6:
Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;
<= ES5
Number.MAX_VALUE;
Number.MIN_VALUE;
console.log('MIN_VALUE', Number.MIN_VALUE);
console.log('MAX_VALUE', Number.MAX_VALUE);
console.log('MIN_SAFE_INTEGER', Number.MIN_SAFE_INTEGER); //ES6
console.log('MAX_SAFE_INTEGER', Number.MAX_SAFE_INTEGER); //ES6
评论
Number.MIN_VALUE
-Number.MAX_VALUE
Number.MAX_VALUE
2^53
Number.MIN_SAFE_INTEGER
Number.MAX_SAFE_INTEGER
JavaScript 有两种数字类型:Number
和 BigInt
。
最常用的数字类型是 64 位浮点 IEEE 754 数字。Number
此类型的最大精确整数值是 Number.MAX_SAFE_INTEGER,
即:
- 253-1,或
- +/- 9,007,199,254,740,991,或
- 九万亿 七万亿 一百九十九亿 二百五十四百万 七十四万 九百九十一
从这个角度来看:一千万亿字节是 PB(或一千 TB)。
在这种情况下,“安全”是指准确表示整数并正确比较它们的能力。
请注意,所有大小为 no 的正整数和负整数 大于 253 在类型中可表示(实际上, 整数 0 有两种表示形式,+0 和 -0)。
Number
为了安全地使用大于此值的整数,您需要使用 BigInt
,它没有上限。
请注意,按位运算符和移位运算符对 32 位整数进行运算,因此在这种情况下,最大安全整数为 231-1,即 2,147,483,647。
const log = console.log
var x = 9007199254740992
var y = -x
log(x == x + 1) // true !
log(y == y - 1) // also true !
// Arithmetic operators work, but bitwise/shifts only operate on int32:
log(x / 2) // 4503599627370496
log(x >> 1) // 0
log(x | 1) // 1
关于数字 9,007,199,254,740,992 主题的技术说明:此值有一个精确的 IEEE-754 表示形式,您可以从变量中分配和读取此值,因此对于小于或等于此值的整数域中非常仔细选择的应用程序,您可以将其视为最大值。
在一般情况下,必须将此 IEEE-754 值视为不准确,因为它编码的逻辑值是 9,007,199,254,740,992 还是 9,007,199,254,740,993 是不明确的。
评论
4294967295 === Math.pow(2,32) - 1;
Firefox 3 似乎对大量数字没有问题。
1e+200 * 1e+100 将计算为 1e+300。
Safari似乎也没有问题。(郑重声明,如果其他人决定测试这一点,这是在 Mac 上。
除非我在一天中的这个时候失去了大脑,否则这比 64 位整数要大得多。
评论
100000000000000010 - 1 => 100000000000000020
我用公式 X-(X+1)=-1 做了一个简单的测试,我可以在 Safari、Opera 和 Firefox(在 OS X 上测试)上获得的最大 X 值是 9e15。这是我用于测试的代码:
javascript: alert(9e15-(9e15+1));
评论
9000000000000000
9000000000000000
1
90*10^14
尝试:
maxInt = -1 >>> 1
在 Firefox 3.6 中,它是 2^31 - 1。
评论
^
^
101
010
5(101) ^ 2(010) = 7(111)
Math.pow()
^
它是 253 == 9 007 199 254 740 992。这是因为 s 以浮点形式存储在 52 位尾数中。Number
最小值为 -253。
这使得一些有趣的事情发生
Math.pow(2, 53) == Math.pow(2, 53) + 1
>> true
也可能是危险的:)
var MAX_INT = Math.pow(2, 53); // 9 007 199 254 740 992
for (var i = MAX_INT; i < MAX_INT + 2; ++i) {
// infinite loop
}
延伸阅读:http://blog.vjeux.com/2010/javascript/javascript-max_int-number-limits.html
评论
i += 1000000000
简短的回答是“视情况而定”。
如果在任何地方使用按位运算符(或者引用的是 Array 的长度),则范围为:
无符号:0…(-1>>>0)
签署:(-(-1>>>1)-1)…(-1>>>1)
(碰巧的是,按位运算符和数组的最大长度限制为 32 位整数。
如果不使用按位运算符或使用数组长度:
签署:(-Math.pow(2,53))…(+Math.pow(2,53))
这些限制是由“数字”类型的内部表示施加的,该表示形式通常对应于 IEEE 754 双精度浮点表示。(请注意,与典型的有符号整数不同,负限的大小与正限的大小相同,这是由于内部表示的特征,实际上包括负 0!
评论
为了安全起见
var MAX_INT = 4294967295;
推理
我以为我会很聪明,用更务实的方法找到价值。x + 1 === x
我的机器每秒只能数 1000 万左右......所以我会在 28.56 年后发回明确的答案。
如果你等不了那么久,我敢打赌
- 您的大多数循环不会运行 28.56 年
9007199254740992 === Math.pow(2, 53) + 1
足以证明- 您应该坚持这样做,以避免位移的预期问题
4294967295
Math.pow(2,32) - 1
发现:x + 1 === x
(function () {
"use strict";
var x = 0
, start = new Date().valueOf()
;
while (x + 1 != x) {
if (!(x % 10000000)) {
console.log(x);
}
x += 1
}
console.log(x, new Date().valueOf() - start);
}());
评论
在 Google Chrome 内置的 javascript 中,您可以在该数字称为无穷大之前转到大约 2^1024。
评论
在 JavaScript 中,有一个数字称为 .Infinity
例子:
(Infinity>100)
=> true
// Also worth noting
Infinity - 1 == Infinity
=> true
Math.pow(2,1024) === Infinity
=> true
对于有关此主题的一些问题,这可能就足够了。
评论
min
Infinity - 1 === Infinity
1 - Infinity === -Infinity
要用于按位运算的任何内容都必须介于 0x80000000(-2147483648 或 -2^31)和 0x7fffffff(2147483647 或 2^31 - 1)之间。
控制台会告诉你 0x80000000 等于 +2147483648,但 0x80000000 & 0x80000000 等于 -2147483648。
Jimmy 的答案正确地将连续的 JavaScript 整数谱表示为 -9007199254740992 以9007199254740992包容性(对不起,9007199254740993,你可能认为你9007199254740993,但你错了!下面或在 jsfiddle 中演示)。
console.log(9007199254740993);
然而,没有答案可以以编程方式找到/证明这一点(除了 CoolAJ86 在他的答案中提到的将在 28.56 年;)完成的答案,所以这里有一个稍微更有效的方法(准确地说,它在大约 28.559999999968312 年:)更有效,还有一个测试小提琴:
/**
* Checks if adding/subtracting one to/from a number yields the correct result.
*
* @param number The number to test
* @return true if you can add/subtract 1, false otherwise.
*/
var canAddSubtractOneFromNumber = function(number) {
var numMinusOne = number - 1;
var numPlusOne = number + 1;
return ((number - numMinusOne) === 1) && ((number - numPlusOne) === -1);
}
//Find the highest number
var highestNumber = 3; //Start with an integer 1 or higher
//Get a number higher than the valid integer range
while (canAddSubtractOneFromNumber(highestNumber)) {
highestNumber *= 2;
}
//Find the lowest number you can't add/subtract 1 from
var numToSubtract = highestNumber / 4;
while (numToSubtract >= 1) {
while (!canAddSubtractOneFromNumber(highestNumber - numToSubtract)) {
highestNumber = highestNumber - numToSubtract;
}
numToSubtract /= 2;
}
//And there was much rejoicing. Yay.
console.log('HighestNumber = ' + highestNumber);
评论
x++
++x
Node.js 和 Google Chrome 似乎都使用 1024 位浮点值,因此:
Number.MAX_VALUE = 1.7976931348623157e+308
评论
2^53
MAX_SAFE_INT
其他人可能已经给出了通用答案,但我认为给出一种快速确定它的方法是个好主意:
for (var x = 2; x + 1 !== x; x *= 2);
console.log(x);
这让我在 Chrome 30 中不到一毫秒的时间内9007199254740992。
它将测试 2 的幂,以找出哪一个,当“添加”1 时,等于他自己。
评论
ECMAScript 6:
Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;
评论
MAX_SAFE_INTEGER
Math.pow(2, 53)-1
我是这样写的:
var max_int = 0x20000000000000;
var min_int = -0x20000000000000;
(max_int + 1) === 0x20000000000000; //true
(max_int - 1) < 0x20000000000000; //true
int32 相同
var max_int32 = 0x80000000;
var min_int32 = -0x80000000;
斯卡托写道:
要用于按位运算的任何内容都必须介于 0x80000000(-2147483648 或 -2^31)和0x7fffffff(2147483647 或 2^31 - 1).
控制台会告诉您 0x80000000 等于 +2147483648,但是 0x80000000 & 0x80000000 等于 -2147483648
十六进制小数是无符号正值,所以 0x80000000 = 2147483648 - 这在数学上是正确的。如果要使它成为有符号值,则必须右移:0x80000000 >> 0 = -2147483648。您也可以改写 1 << 31。
许多早期的答案都表明是正确的,以验证 9,007,199,254,740,991 是最大和安全的整数。9007199254740992 === 9007199254740992 + 1
但是,如果我们继续做积累呢?
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 位。
来自维基百科(有关更多详细信息,请访问此处)
因此,要使指数部分为 2^52,我们正好需要设置 e = 1075。
让我们来看看源头
描述
常量的值为 (9,007,199,254,740,991 或 ~9 千万亿)。该数字背后的原因是 JavaScript 使用 IEEE 754 中指定的双精度浮点格式数字,并且只能安全地表示介于 和 之间的数字。
MAX_SAFE_INTEGER
9007199254740991
-(2^53 - 1)
2^53 - 1
在这种情况下,安全是指准确表示整数并正确比较它们的能力。例如,将计算结果为 true,这在数学上是不正确的。有关更多信息,请参见 Number.isSafeInteger()。
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
由于是 Number 的静态属性,因此始终将其用作 ,而不是您创建的 Number 对象的属性。
MAX_SAFE_INTEGER
Number.MAX_SAFE_INTEGER
浏览器兼容性
在 JavaScript 中,数字的表示形式是 。2^53 - 1
但是,按位运算
是按 32 位(4 字节)
计算的,这意味着如果超过 32 位移位,您将开始丢失位。
评论
JavaScript 在 ECMAScript 2020 中获得了一种新的数据类型:.它引入了具有“n”后缀的数字文字,并允许任意精度:BigInt
var a = 123456789012345678901012345678901n;
当然,当如此大的整数被强制(可能是无意的)强制转换为数字数据类型时,精度仍然会丢失。
而且,显然,由于内存有限,总是会存在精度限制,并且为了分配必要的内存和对如此大的数字执行算术运算,总会存在时间成本。
例如,生成一个具有十万位十进制数字的数字,在完成之前需要明显的延迟:
console.log(BigInt("1".padEnd(100000,"0")) + 1n)
...但它有效。
评论
1n << 10000n
n
BigInt
BigInt