关于math:JavaScript的最高整数值是多少,而且不会丢失精度?

What is JavaScript's highest integer value that a number can go to without losing precision?

这是由语言定义的吗?是否有定义的最大值?在不同的浏览器中它是不同的吗?


+/-9007199254740991

ECMA第8.5节-数字

Note that all the positive and negative integers whose magnitude is no greater than 253 are representable in the Number type (indeed, the integer 0 has two representations, +0 and ?0).

它们是64位浮点值,最大的精确整数值是253-1或9007199254740991。在ES6中,这被定义为number.max_safe_integer。

请注意,位运算符和移位运算符对32位整数进行操作,因此在这种情况下,最大安全整数为231-1或2147483647。

试一试!

1
2
3
4
5
6
7
8
var x = 9007199254740992;
var y = -x;
x == x + 1; // true !
y == y - 1; // also true !
// Arithmetic operators work, but bitwise/shifts only operate on int32:
x / 2;      // 4503599627370496
x >> 1;     // 0
x | 1;      // 1

关于数字9007199254740992主题的技术说明:该值有一个确切的IEEE-754表示,您可以从变量中分配和读取该值,因此对于在小于或等于该值的整数域中精心选择的应用程序,您可以将其视为最大值。

在一般情况下,必须将此IEEE-754值视为不精确值,因为它对逻辑值9007199254740992或9007199254740993的编码不明确。


> ES6:
Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

参考文献:
Number.MAX_VALUE;
Number.MIN_VALUE;

1
2
3
4
5
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


它是253==9 007 199 254 740 992。这是因为Numbers以52位尾数的形式存储为浮点。

最小值为-253。

这让一些有趣的事情发生

1
2
Math.pow(2, 53) == Math.pow(2, 53) + 1
>> true

也可能是危险的。)

1
2
3
4
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


在javascript中,有一个称为Infinity的数字。

实例:

1
2
3
4
5
6
7
8
9
(Infinity>100)
=> true

// Also worth noting
Infinity - 1 == Infinity
=> true

Math.pow(2,1024) === Infinity
=> true

对于有关此主题的某些问题,这可能已经足够了。


吉米的答案正确地代表了连续的javascript整数谱,即-9007199254740992到9007199254740992(对不起,9007199254740993,你可能认为你是9007199254740993,但你错了!下面或jsiddle中的演示)。

1
document.write(9007199254740993);

然而,没有任何答案可以通过程序来发现/证明这一点(除了Coolaj86在他的答案中提到的将在28.56年内完成的答案);因此,这里有一个稍微更有效的方法来做到这一点(准确地说,它在28.5599999968312年内效率更高):以及一个测试小提琴:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/**
 * 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);


为了安全

1
var MAX_INT = 4294967295;

推理

我认为我会很聪明,并且发现EDCOX1的7值更实用。

我的机器每秒只能计算1000万个…因此,我将在28.56年后回复明确的答案。

如果你不能等那么久,我敢打赌

  • 你的大部分循环都是28.56年不运行的。
  • 9007199254740992 === Math.pow(2, 53) + 1足以证明
  • 您应该坚持使用4294967295,即Math.pow(2,32) - 1,以避免出现位移的预期问题。

发现x + 1 === x

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
(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);
}());


ECMAScript 6:

1
2
Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;


简短的回答是"视情况而定"。

如果在任何地方使用位运算符(或者如果引用数组的长度),则范围为:

未签字:0…(-1>>>0)

签字:(-(-1>>>1)-1)…(-1>>>1)

(因此,位运算符和数组的最大长度被限制为32位整数。)

如果不使用位运算符或使用数组长度:

符号:(-Math.pow(2,53))…(+Math.pow(2,53))

这些限制是由"数字"类型的内部表示强加的,它通常对应于IEEE 754双精度浮点表示。(注意,与典型的有符号整数不同,负极限的大小与正限的大小相同,这是由于内部表示的特性,它实际上包括负0)。


前面的许多答案显示了9007199254740992 === 9007199254740992 + 1的结果true说明9 007 199 254 740 991是最大安全整数。

如果我们继续做积累呢:

1
2
3
4
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。

我们从503 599 627 370 496开始,先简要介绍一下格式:

1
2
  1 . 0000 ---- 0000  *  2^52            =>  1  0000 ---- 0000.  
     |-- 52 bits --|    |exponent part|        |-- 52 bits --|

在箭头的左边,我们有位值1和一个相邻的基数点,然后通过乘以2^52,我们向右移动基数点52步,它将到达末尾。现在我们得到了二进制的4503599627370496。

现在,我们开始将1累加到这个值,直到所有的位都设置为1,这等于9 007 199 254 740 991(十进制)。

1
2
3
4
5
6
7
8
9
10
  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,并操作指数部分:

1
2
3
4
5
6
7
8
9
10
11
12
  |--> This bit is implicit and persistent.
  |        
  1 . 1111 ---- 1111  *  2^52      =>  1  1111 ---- 1111.
     |-- 52 bits --|                     |-- 52 bits --|

                          (+1)
                                     (radix point has no way to go)
  1 . 0000 ---- 0000  *  2^52 * 2  =>  1  0000 ---- 0000. * 2  
     |-- 52 bits --|                     |-- 52 bits --|

  =>  1 . 0000 ---- 0000  *  2^53
         |-- 52 bits --|

现在我们得到9 007 199 254 740 992,如果数字大于9 007 199 254 740 992,那么格式可以容纳2倍的分数:

1
2
3
                            (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倍的分数可以保持:

1
2
3
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
2
 1 . 0000 ---- 0001  *  2^51  =>  1 0000 ---- 000.1
     |-- 52 bits --|                |-- 52 bits  --|

基点后的位值1为2~1。(=1/2,=0.5)因此,当数字小于4 503、599、627、370、496(2 ^ 52)时,有一个位可用以表示整数的1/2倍:

1
2
input: 4503599627370495.5   output: 4503599627370495.5  
input: 4503599627370495.75  output: 4503599627370495.5

小于2,251,799,813,685,248(2 ^ 51)

1
2
3
4
5
6
7
8
9
10
11
12
13
input: 2251799813685246.75   output: 2251799813685246.8  // expected: 2251799813685246.75
input: 2251799813685246.25   output: 2251799813685246.2  // expected: 2251799813685246.25
input: 2251799813685246.5    output: 2251799813685246.5

// If the digits exceed 17, JavaScript round it to print it.
//, but the value is 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位。来自wiki的完整格式:(有关详细信息,请转到那里)

IEEE 754 Double Floating Point Format.svg

enter image description here

所以要获得2^52的指数部分,我们需要设置e=1075。


其他人可能已经给出了一般性的答案,但我认为最好给出一个快速确定的方法:

1
2
for (var x = 2; x + 1 !== x; x *= 2);
console.log(x);

这给了我9007199254740992在不到一毫秒的铬30。

它将测试2的幂,以确定当"添加"1时,哪一个等于自己。


要用于逐位运算的任何内容都必须介于0x8000000(-2147483648或-2^31)和0x7fffffff(2147483647或2^31-1)之间。

控制台将告诉您,0x8000000等于+2147483648,而0x8000000&0x8000000等于-2147483648。


尝试:

1
maxInt = -1 >>> 1

在火狐3.6中是2^31-1。


我用公式x-(x+1)=-1做了一个简单的测试,在Safari、Opera和Firefox(在OS ;x上测试)上我能得到的最大x值是9e15。以下是我用于测试的代码:

1
javascript: alert(9e15-(9e15+1));


我是这样写的:

1
2
3
4
var max_int = 0x20000000000000;
var min_int = -0x20000000000000;
(max_int + 1) === 0x20000000000000;  //true
(max_int - 1) < 0x20000000000000;    //true

相同的32

1
2
var max_int32 =  0x80000000;
var min_int32 = -0x80000000;


在google chrome内置的javascript中,您可以在数字被称为无穷大之前转到大约2^1024。


我们到源头去吧描述

The MAX_SAFE_INTEGER constant has a value of 9007199254740991 (9,007,199,254,740,991 or ~9 quadrillion). The reasoning behind that number is that JavaScript uses double-precision floating-point format numbers as specified in IEEE 754 and can only safely represent numbers between -(253 - 1) and 253 - 1.

Safe in this context refers to the ability to represent integers exactly and to correctly compare them. For example, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 will evaluate to true, which is mathematically incorrect. See Number.isSafeInteger() for more information.

Because MAX_SAFE_INTEGER is a static property of Number, you always use it as Number.MAX_SAFE_INTEGER, rather than as a property of a Number object you created.

浏览器兼容性

enter image description here


在编写时,javascript正在接收一种新的数据类型:BigInt。这是第3阶段的TC39提案。BigInt有Chrome67+、Firefox 67+(需要激活选项)、Opera54和节点10.4.0。它正在Safari等地进行。它引入具有"n"后缀的数字文本,并允许任意精度:

1
var a = 123456789012345678901012345678901n;

当然,当这种数字(可能是无意中)被强制为数字数据类型时,精度仍然会丢失。


当数字大于2时,功率为53 Ie。

1
Math.pow(2, 53)

javascript知道它是一个大整数。然后,javascript将它们存储为"bigint",因此与'bigint'==='bigint'相比就变成了现实。

将它们的值存储在数学对象本身中的更安全的方法。

1
2
3
const bigInt1 = Math.pow(2, 55)
const bigInt2 = Math.pow(2, 66)
console.log(bigInt1 === bigInt2) // false

SCATO WROTES:

anything you want to use for bitwise operations must be between
0x80000000 (-2147483648 or -2^31) and 0x7fffffff (2147483647 or 2^31 -
1).

the console will tell you that 0x80000000 equals +2147483648, but
0x80000000 & 0x80000000 equals -2147483648

十六进制小数是无符号正值,所以0x8000000=2147483648-这在数学上是正确的。如果要使其成为有符号值,必须右移:0x8000000>>0=-2147483648。你也可以写1<<31。


number.max_value表示javascript中可表示的最大数值。

因为似乎没有人这样说过,在V8引擎中,EDOCX1的行为和0的数量和数量在行为上是有差异的。

如果你有EDCOX1,1,你可以使用第一个比特告诉JavaScript引擎数据是什么类型,剩下的位包含实际数据。这就是V8作为EDOCX1的2个EDCOX1(3)所做的一个小优化(或者用来做的,我的数据源非常过时)。最后一个EDOCX1,0是数字值,然后是第一位告诉引擎,它是一个数字或一个对象引用。

但是,如果你使用EDOCX1以上0的数字,那么数据将不适合,这个数字将被装箱64位一倍,优化不会在那里。

在下面的视频中,底线是:

prefer numeric values that can be represented as 31bits signed
integers.

  • 有趣的视频
  • 其他来源

基本上,javascript不支持long。因此,对于可以表示小于32位的正常值,它将使用int类型的容器。对于大于32位的整数值,它使用double。在双重表示中,整数部分是53位,其余部分是尾数(保留浮点信息)。所以你可以用2^53 - 1,它的值是9007199254740991。您可以访问Number.MAX_SAFE_INTEGER在代码中使用的值。


在javascript中,数字的表示是2^53 - 1

然而,Bitwise operation是在32 bits ( 4 bytes )上计算的,这意味着如果超过32位移位,就会开始丢失位。


node.js和google chrome似乎都在使用1024位浮点值,因此:

1
Number.MAX_VALUE = 1.7976931348623157e+308


firefox 3似乎对庞大的数字没有问题。

1e+200*1e+100将计算为1e+300。

狩猎似乎也没什么问题。(据记录,如果有其他人决定测试,这是在Mac上进行的。)

除非我在一天中的这个时候失去了理智,否则这比一个64位整数要大得多。