一个数字可以在不损失精度的情况下达到的JavaScript的最高整数值是多少?


951

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


5
你并不需要依赖于JS与像库限制 github.com/MikeMcl/big.js,例如参见这里的可靠性测试
德米特里·扎伊采夫

2
big.js可以使用的最大整数值是多少?
乔治

@George这是big.js API:mikemcl.github.io/big.js/#dp
simhumileco

这个问题没有道理。数字“转到”整数值是什么意思?如果您只想问问JS中可以代表的最高整数是多少,最高(有限)数本身就是一个整数。
Veky

@DmitriZaitsev我们不再需要依赖外部库了(至少在某些浏览器上)。1n << 10000n是一个非常非常大的整数,不会失去任何精度,也不需要任何依赖项(不用说,甚至没有接近极限)。
阿玛丹

Answers:


867

JavaScript有两种数字类型:NumberBigInt

最常用的数字类型Number为64位浮点IEEE 754数字。

该类型的最大精确整数值为Number.MAX_SAFE_INTEGER,即:

  • 2 53 -1,或
  • +/- 9,007,199,254,740,991,或
  • 九四十亿七千七百亿一百九十二亿一千二百四十五万一四十九万一千九十一

从一个角度来看:一个四兆字节是PB(或一千TB)。

在本文中,“安全”是指能够准确表示整数并正确比较它们的能力。

从规格:

请注意,所有大小不大于2 53的正整数和负整数都可以在该Number类型中表示(实际上,整数0具有+0和-0两种表示形式)。

为了安全地使用大于此值的整数,您需要使用BigInt,没有上限。

请注意,按位运算符和移位运算符对32位整数进行运算,因此在这种情况下,最大安全整数为2 31 -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都是模棱两可的。


75
这似乎是正确的,但是在哪里定义了它,例如C的MAX_INT或Java的Integer.MAX_VALUE?
塔拉玛

48
4294967295 === Math.pow(2,32) - 1;
CoolAJ86

13
那么,可以用来确保精确度的最小和最大整数是多少?
Pacerier,2011年

38
可能值得注意的是,javascript中没有实际的(int)。Number的每个实例都是(float)或NaN。
甜菜根-甜菜根

53
9007199254740992并不是最大值,此处的最后一位已被假定为零,因此您失去了1位精度。实际的安全号码是9007199254740991(Number.MAX_SAFE_INTEGER)
Willem D'Haeseleer 2014年

461

> = ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

<= ES5

参考

Number.MAX_VALUE;
Number.MIN_VALUE;


23
我对问题进行了更精确的编辑,以获取最大的Integer值,而不仅仅是最大的Number值。很抱歉给您带来混乱。
塔拉玛

5
返回的结果是否保证在所有浏览器上都相等?
起搏器

7
请注意,这Number.MIN_VALUE是最小的数。该至少值(即小于其他东西)是可能-Number.MAX_VALUE
Michael Scheper 2014年

34
ES6引入Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER
superlukas

2
因此,在这种情况下,我们是否应该因为对最新问题的回答是错误的而否决答案,还是因为彼得·贝利(Peter Baily)在回答问题时是对的而留下答案?
火箭快

112

它是2 53 == 9 007 199 254 740 740992。这是因为Numbers作为浮点存储在52位尾数中。

最小值是-2 53

这使一些有趣的事情发生了

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


1
尽管您永远都不会在合理的时间内到达for循环的终点,但您可能还是想说i += 1000000000
ninjagecko 2015年

2
@ninjagecko,他从MAX_INT开始,所以终点就在那里。同样使用i + = 1000000000将使其不再是无限循环。尝试一下。
Ted Bigham

@TedBigham:糟糕,准备得太快了。感谢您两次纠正我。
ninjagecko

见吉米的论据9,007,199,254,740,991,而不是9,007,199,254,740,992 这里。结合我的后续行动,这似乎很有说服力。
TJ Crowder

60

在JavaScript中,有一个名为的数字Infinity

例子:

(Infinity>100)
=> true

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

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

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


25
告诉我无穷大不符合整数。:)
devios1 2012年

7
但是,min当您寻找最小值时,足以初始化一个变量。
djjeck 2012年

9
请注意Infinity - 1 === Infinity
H.Wolper

2
也(Infinity <100)=> false和Math.pow(2,1024)=== Infinity
Sijav

6
同样值得一提的是它也可以处理负无穷大。所以1 - Infinity === -Infinity
dmccabe 2014年

41

Jimmy的答案正确地将连续的JavaScript整数频谱表示为-90071992547409929007199254740992(包括9007199254740993(很抱歉,您可能认为您是9007199254740993,但您错了! jsfiddle中或以下的演示)。

console.log(9007199254740993);

但是,没有以编程方式找到/证明这一问题的答案(除了在他的答案中提到的将在28.56 年内完成的CoolAJ86之外;),所以这是一种更有效的方法(确切地说,它更有效大约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);


8
@ CoolAJ86:大声笑,我期待2040年3月15日。如果我们的数字匹配,我们应该
举办

var x = Math.pow(2,53)-3; while(x!= x + 1)x ++; -> 9007199254740991
MickLH 2013年

@MickLH:我得到的代码是 9007199254740992 。您正在使用哪种JavaScript引擎进行测试?
Briguy37 2013年

使用您自己的代码,您将获得9007199254740992,我没有使用x的最终值,而是出于偏执的原因使用了x ++的最终评估。谷歌浏览器顺便说一句。
MickLH 2013年

@MickLH:评估x++会在增量发生之前为您提供x的值,因此很可能可以解释差异。如果您希望表达式的计算结果与x的最终值相同,则应将其更改为++x
peterflynn

32

为了安全起见

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);
}());

4
您不能以2 ^ 53-2进行测试吗?(是的,您可以尝试,即使是-3也是安全的:var x = Math.pow(2,53)-3; while(x!= x + 1)x ++;)-> 9007199254740991
MickLH

好答案!此外,我知道该值已确定,但为什么不使用二进制搜索来查找呢?
higuaro 2014年

1
那有什么乐趣?此外,@ Briguy37击败了我:stackoverflow.com/a/11639621/151312
CoolAJ86 2014年

请注意,与日期值比较时,基于32位的“安全” MAX_INT将不起作用。4294967295昨天是如此!
杰里

1
答案“为了安全:var MAX_INT = 4294967295;” 不幽默 如果您不进行移位,则不必担心(除非您需要大于4294967295的int,在这种情况下,您可能应该将其存储为字符串并使用bigint库)。
CoolAJ86 2014年

29

简短的答案是“取决于情况”。

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

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

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

(碰巧将按位运算符和数组的最大长度限制为32位整数。)

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

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

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


这是我想在如何将X转换为32位整数或无符号整数的答案。为此建议了您的答案。
Charlie Affumigato

29

ECMAScript 6:

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

1
请注意 ,并非所有浏览器都支持此功能!如今,iOS(甚至不是Chrome),Safari和IE都不喜欢它。
cregox 2015年

5
请仔细阅读答案,我们未使用ECMAScript 6中Number.MAX_SAFE_INTEGER的默认实现,而是由Math.pow(
2,53

我认为这只是在ECMA 6中如何实施的参考!:PI认为我的评论仍然有效。一切都取决于上下文。;)
cregox

3
MAX_SAFE_INTEGER通过向后工作在所有浏览器中进行计算是否可靠?您应该前进吗?即Number.MAX_SAFE_INTEGER = 2 *(Math.pow(2,52)-1)+ 1;
kjv 2015年

Math.pow(2, 53)-1一个安全的操作?它比最大安全整数大一。
ioquatix

21

从早期的许多答案都显示出结果true9007199254740992 === 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使用这种二进制格式保存(表示)。

使用简短的版本从4503599627370496进行演示:

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

在箭头的左侧,我们有位值1和一个相邻的小数点,然后乘以2^52,我们将小数点右移52步,然后到最后。现在我们以二进制形式获得4503599627370496。

现在,我们开始将1累加到该值,直到所有位都设置为1,即十进制等于9007199254254740991

  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位用于小数,因此再也没有位可用于加一,因此,我们要做的就是将所有位都设置回0,然后操作指数部分:

  |--> 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 740 992,数字大于它,格式可以容纳分数的2倍,这意味着分数部分上每加1实际上等于2加法,这就是为什么double当数字大于9007 199 254 740 740 992时,精度64位二进制格式不能包含奇数:

                            (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 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 2484 503 599 627 370 496)?

 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倍

input: 4503599627370495.5   output: 4503599627370495.5  
input: 4503599627370495.75  output: 4503599627370495.5  

少于2251799813685248(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

// 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双浮点格式

在此处输入图片说明

因此,要使指数部分为2 ^ 52,我们确实需要设置e = 1075。


13

其他人可能已经给出了通用答案,但是我认为提供一种快速的方法来确定它是一个好主意:

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

在Chrome 30中不到一毫秒的时间内,我得到了9007199254740992。

它将测试2的幂,以发现“加” 1时哪个等于自己。


想,这可能会使您的应用程序崩溃。
Sapphire_Brick

8

您要用于按位运算的任何值都必须在0x80000000(-2147483648或-2 ^ 31)和0x7fffffff(2147483647或2 ^ 31-1)之间。

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


6

尝试:

maxInt = -1 >>> 1

在Firefox 3.6中为2 ^ 31-1。


2
@danorton:我不确定您了解自己在做什么。^提高权力。在Javascript控制台中,^XOR而不是引发
kumarharsh 2013年

2
打开Chrome / Firefox控制台。输入5 ^ 2。在二进制中,5是101,2是010。现在,如果你位异或他们,你会得到5(101) ^ 2(010) = 7(111) READ这一点,如果你困惑 这里正在讨论是Math.pow()不是^运营商
kumarharsh

3
同样,我一点也不困惑。我对所写的内容发表了评论和不满。如果Math.pow()是什么意思,那就应该写什么。在回答有关JavaScript的问题时,不宜使用其他语言的语法。使用在JavaScript中有效但在JavaScript中具有与预期含义不同的解释的语法甚至更不合适。
danorton 2013年

10
2 ^ 31是一个人用英语将二写为第一十一的幂的方式。它不在代码块中。您是否会抱怨有人使用;在一个答案中,因为这是Javascript中具有不同含义的字符?
lmm 2014年

3
即使一个人应该用纯文本写2³¹而不是2 ^ 31也是常见的做法,因为默认情况下大多数键盘布局都不包含那些字符。至少我对理解这个答案的含义没有任何问题。
Jocke

6

在撰写本文时,JavaScript正在接收一种新的数据类型:BigInt。这是TC39提案的第4阶段,将包含在EcmaScript 2020中BigInt适用于Chrome 67 +,FireFox 68 +,Opera 54和Node 10.4.0。它正在Safari等系统中进行。它引入了带有“ n”后缀的数字文字,并允许任意精度:

var a = 123456789012345678901012345678901n;

当然,当这样的数字(可能是无意间)强制转换为数字数据类型时,精度仍然会丢失。

并且,显然,由于有限的存储器而总是存在精度限制,并且为了分配必要的存储器并且对如此大的数字执行算术在时间方面存在成本。

例如,生成具有十万个十进制数字的数字将在完成之前花费明显的延迟:

console.log(BigInt("1".padEnd(100000,"0")) + 1n)

...但是有效。


4

我使用公式X-(X + 1)=-1进行了简单测试,并且XI可以在Safari,Opera和Firefox上运行(在OS X上测试过)的最大值是9e15。这是我用于测试的代码:

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

1
请注意,9e15 = 2 ^ 53(请参阅@Jimmy的答案)。
楔子

6
9e15 =9000000000000000。2 ^ 53 =9007199254740992。因此,9e15大约等于2 ^ 53(有两个有效数字),因此很有趣。
devios1 2012年

@chaiguy中9000000000000000有1个重要数字。在“ 9007199254740992”中,有15个有效数字。
罗伊·纳米尔

@RoyiNamir不想在这里开始毫无意义的争论,但是9000000000000000有16位有效数字。如果只需要1,则必须写为9x10 ^ 15。
devios1

1
@chaiguy号9000000000000000-是1SF。其中90*10^14有2(sigfigscalculator.appspot.commathsfirst.massey.ac.nz/Algebra/Decimals/SigFig.htm(底部)
Royi纳米尔

3

我这样写:

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;

3

让我们来看看资源

描述

MAX_SAFE_INTEGER常数的值为9007199254740991(9,007,199,254,740,991或〜9万亿)。该数字背后的原因是,JavaScript使用IEEE 754中指定的双精度浮点格式数字,并且只能安全地表示介于和之间的数字。-(2^53 - 1)2^53 - 1

在此上下文中,安全是指能够精确表示整数并正确比较它们的能力。例如,Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2将评估为true,这在数学上是不正确的。请参见Number.isSafeInteger()更多信息,。

因为MAX_SAFE_INTEGERNumber的静态属性,所以您始终将其用作Number.MAX_SAFE_INTEGER,而不是用作创建的Number对象的属性。

浏览器兼容性

在此处输入图片说明




-1

斯卡托写道:

您要用于按位运算的任何值都必须在0x80000000(-2147483648或-2 ^ 31)和0x7fffffff(2147483647或2 ^ 31-1)之间。

控制台会告诉您0x80000000等于+2147483648,但0x80000000&0x80000000等于-2147483648

十六进制小数是无符号正值,因此0x80000000 = 2147483648-在数学上正确。如果要使其为有符号值,则必须右移:0x80000000 >> 0 = -2147483648。您也可以写1 << 31。


-7

Firefox 3似乎在数量上没有问题。

1e + 200 * 1e + 100将精确到1e + 300。

Safari似乎也没有问题。(出于记录目的,如果有其他人决定对此进行测试,则它在Mac上。)

除非我在一天中的这个时候迷失了头脑,否则它比64位整数大得多。


18
它不是64位整数,而是64位浮点数,其中52/53位是整数部分。因此它最多可以处理1e300,但不精确。
吉米

4
吉米是正确的。在浏览器或JS命令行中尝试以下操作:100000000000000010 - 1 => 100000000000000020
Ryan

-7

Node.js和Google Chrome似乎都使用1024位浮点值,因此:

Number.MAX_VALUE = 1.7976931348623157e+308

1
-1:最大可表示(非精确整数)数可能是〜2 ^ 1024,但这并不意味着它们偏离IEEE-754 64位标准。
罗伊·廷克

2
MAX_INT?您是说MAX_VALUE吗?
劳尔·基乌

3
这是浮点值的最大值。这并不意味着您可以存储一个int这么长的时间
phuclv

1
甚至更重要的是,您不能可靠地存储一个int这么长时间而不会损失准确性2^53之所以称为,是MAX_SAFE_INT因为在该点之上,值以近似的方式变为近似值。
IMSoP 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.