ChatGPT解决这个技术问题 Extra ChatGPT

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

这是由语言定义的吗?有定义的最大值吗?不同浏览器有区别吗?

您不需要依赖 JS 对 github.com/MikeMcl/big.js 等库的限制,请参阅 here for its reliability tests
big.js 可以使用的最高整数值是多少?
@DmitriZaitsev 我们不再需要依赖外部库(至少在某些浏览器上)。 1n << 10000n 是一个非常非常大的整数,不会丢失任何精度,不需要任何依赖项(不用说,甚至没有接近极限)。
@DmitriZaitsev 注意 n 后缀。 BigInt 类是 ES2020 规范草案的一部分,已在大多数浏览器中实现;您可以尝试在没有外部库的情况下在 Chrome 或 Firefox 中进行评估,并获得 3011 位的 BigInt
@DmitriZaitsev:是的,它仅适用于整数。这个问题是关于整数的。

B
BobSfougaroudis

JavaScript 有两种数字类型:NumberBigInt

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

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

253-1,或

+/- 9,007,199,254,740,991,或

九千万亿 七万亿 一百九千九十亿 七十四万九百九十一

换个角度来看:1 万亿字节是 PB(或 1000 TB)。

在这种情况下,“安全”是指准确表示整数并正确比较它们的能力。

From the spec:

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

要安全地使用大于此的整数,您需要使用没有上限的 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) // 也是如此! // 算术运算符有效,但按位/移位仅在 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 进行编码是不明确的。


这似乎是对的,但是在某个地方定义了它,比如 C 的 MAX_INT 或 Java 的 Integer.MAX_VALUE?
4294967295 === Math.pow(2,32) - 1;
那么我们可以用来确保精确度的最小和最大整数是多少呢?
也许值得注意的是,javascript 中没有实际的 (int)。 Number 的每个实例都是 (float) 或 NaN。
9007199254740992 并不是真正的最大值,这里的最后一位已经假定为零,因此您失去了一位精度。真正的安全号码是 9007199254740991 ( Number.MAX_SAFE_INTEGER )
Z
Zsolt Meszaros

>= ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

<= ES5

the reference

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


我已经编辑了这个问题,使其更准确地了解想要最大 Integer 值,而不仅仅是最大 Number 值。很抱歉造成混乱,在这里。
返回的结果是否保证在所有浏览器上都相同?
请注意,Number.MIN_VALUE 是可能的最小 数。 least 值(即小于其他任何值)可能是 -Number.MAX_VALUE
这是最大浮点值。问题是关于最高整数值。虽然 Number.MAX_VALUE 是一个整数,但您不能超过 2^53 而不会丢失精度。
ES6 引入了 Number.MIN_SAFE_INTEGERNumber.MAX_SAFE_INTEGER
A
Andrew T.

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

最小值为 -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


尽管在合理的时间范围内永远不会到达该 for 循环的结尾,但您可能希望说 i += 1000000000
@ninjagecko,他从 MAX_INT 开始,所以结束就在那里。同样使用 i+= 1000000000 将使其不再是无限循环。试试看。
@TedBigham:啊,哎呀,准备得太快了。谢谢你纠正我两次。
请参阅 Jimmy 对于 9,007,199,254,740,991 而不是 9,007,199,254,740,992 here 的论证。结合我的后续行动,这似乎很有说服力。
P
Peter Mortensen

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

例子:

(Infinity>100)
=> true

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

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

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


有些东西告诉我无穷大不符合整数。 :)
但是,当您在寻找最小值时,初始化一个 min 变量就足够了。
请注意,Infinity - 1 === Infinity
还有 (Infinity<100) => false 和 Math.pow(2,1024) === Infinity
同样毫无价值的是它也可以处理负无穷大。所以1 - Infinity === -Infinity
S
Sapphire_Brick

Jimmy's answer 正确表示连续 JavaScript 整数谱为 -90071992547409929007199254740992 包括在内(对不起 9007199254740993,你可能认为你是 9007199254740993,但你错了!演示下方或在 jsfiddle 中)。

控制台.log(9007199254740993);

但是,没有答案可以以编程方式找到/证明这一点(除了 his answer 中提到的 CoolAJ86 将在 28.56 年内完成;),所以这里有一种更有效的方法(准确地说,它更多效率大约为 28.559999999968312 年 :),以及 test fiddle

/** * 检查一个数字加/减一个是否产生正确的结果。 * * @param number 要测试的数字 * @return 如果可以加/减 1,则返回 true,否则返回 false。 */ var canAddSubtractOneFromNumber = function(number) { var numMinusOne = number - 1; var numPlusOne = 数字 + 1; return ((number - numMinusOne) === 1) && ((number - numPlusOne) === -1); } //找到最大的数字 var highestNumber = 3; //以整数 1 或更高的整数开头 //获取一个大于有效整数范围的数字 while (canAddSubtractOneFromNumber(highestNumber)) {highestNumber *= 2; } //从var numToSubtract =highestNumber / 4中找出你不能加/减1的最小数; while (numToSubtract >= 1) { while (!canAddSubtractOneFromNumber(highestNumber - numToSubtract)) {highestNumber =highestNumber - numToSubtract; } numToSubtract /= 2; } //有很多的欣喜。耶。 console.log('HighestNumber = ' +highestNumber);


@CoolAJ86:大声笑,我期待着 2040 年 3 月 15 日。如果我们的数字匹配,我们应该举办一个派对 :)
var x=Math.pow(2,53)-3;while (x!=x+1) x++; -> 9007199254740991
@MickLH:我用 that code 得到 9007199254740992。您使用什么 JavaScript 引擎进行测试?
你用自己的代码得到 9007199254740992,我没有使用 x 的最终值,而是出于偏执的原因对 x++ 的最终评估。谷歌浏览器顺便说一句。
@MickLH:评估 x++ 为您提供 x before 增量发生的值,因此这可能解释了差异。如果您希望表达式的计算结果与 x 的最终值相同,则应将其更改为 ++x
C
Carr

许多较早的答案显示 9007199254740992 === 9007199254740992 + 1true 以验证 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。这就是为什么当数字大于 9,007,199,254,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,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(有关详细信息,请前往那里)

https://upload.wikimedia.org/wikipedia/commons/thumb/a/a9/IEEE_754_Double_Floating_Point_Format.svg/1200px-IEEE_754_Double_Floating_Point_Format.svg.png

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


c
coolaj86

为了安全

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

你不能从 2^53 - 2 开始测试吗? (是的,你可以,我只是尝试过,即使使用 -3 也是安全的: var x=Math.pow(2,53)-3;while (x!=x+1) x++;) -> 9007199254740991
不错的答案!此外,我知道该值已确定,但为什么不使用二分查找呢?
这有什么好玩的?此外,@ Briguy37 击败了我:stackoverflow.com/a/11639621/151312
请注意,与 Date 值比较时,此基于 32 位的“安全”MAX_INT 将不起作用。 4294967295 昨天就是这样!
答案“为安全起见:var MAX_INT = 4294967295;”不幽默。如果您不进行位移,请不要担心(除非您需要一个大于 4294967295 的 int,在这种情况下您应该将其存储为字符串并使用 bigint 库)。
d
danorton

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

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

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

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

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

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

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

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


这是我想偶然发现的关于如何将 X 转换为 32 位整数或无符号整数的答案。对此表示赞同。
W
WaiKit Kung

ECMAScript 6:

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

小心 this is not (yet) supported by all browsers!今天的 iOS(甚至不是 chrome)、Safari 和 IE 都不喜欢它。
请仔细阅读答案,我们没有使用 ECMAScript 6 中 Number.MAX_SAFE_INTEGER 的默认实现,我们通过 Math.pow(2, 53)-1 定义它
我认为这只是对它在 ECMA 6 中的实现方式的参考! :PI 认为我的评论仍然有效。所有的上下文问题。 ;)
通过向后工作在所有浏览器中计算 MAX_SAFE_INTEGER 是否可靠?你应该继续前进吗?即 Number.MAX_SAFE_INTEGER = 2 * (Math.pow(2, 52) - 1) + 1;
Math.pow(2, 53)-1 操作安全吗?它比最大的安全整数大一。
P
Philippe97

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

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

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

它将测试 2 的幂,以找出哪一个在“加”1 时等于他自己。


它可能会使您的应用程序崩溃,想。
P
Peter Mortensen

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

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


t
trincot

JavaScript 在 ECMAScript 2020 中获得了一种新的数据类型:BigInt。它引入了具有“n”后缀的数字文字并允许任意精度:

var a = 123456789012345678901012345678901n;

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

而且,显然,由于内存有限,总是存在精度限制,并且为了分配必要的内存和对如此大的数字执行算术,需要花费时间。

例如,一个十万十进制数字的生成,在完成之前将需要一个明显的延迟:

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

...但它有效。


P
Peter Mortensen

尝试:

maxInt = -1 >>> 1

在 Firefox 3.6 中,它是 2^31 - 1。


@danorton:我不确定您是否了解自己在做什么。 ^表示获得权力。在 javascript 控制台中,^XOR,而不是提升到
打开 Chrome/Firefox 控制台。键入 5^2。在二进制中,5 是 101,2 是 010。现在,如果您对它们进行按位异或,您将得到 5(101) ^ 2(010) = 7(111) READ THIS IF YOU'RE CONFUSED 这里讨论的是 Math.pow() 而不是 ^ 运算符
再说一次,我一点也不困惑。我对所写的内容发表了评论并投了反对票。如果 Math.pow() 是什么意思,那么这就是应该写的。在回答有关 JavaScript 的问题时,使用不同语言的语法是不合适的。使用在 JavaScript 中有效但在 JavaScript 中的解释与预期含义不同的语法甚至更不合适。
2^31 是一个人用英语写 2 的 31 次方的方式。它不在代码块中。你会抱怨有人使用 ;在一个答案中,因为这是一个在 Javascript 中具有不同含义的字符?
即使一个人应该用纯文本写 2³¹ 而不是 2^31 ,但这样做很常见,因为大多数键盘布局默认情况下都没有这些字符。至少我在理解这个答案的含义时没有任何问题。
P
Peter Mortensen

我用公式做了一个简单的测试,X-(X+1)=-1,XI 的最大值可以在 Safari、Opera 和 Firefox 上工作(在 OS X 上测试)是 9e15。这是我用于测试的代码:

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

请注意 9e15 = 2^53 (请参阅@Jimmy 的回答)。
9e15 = 9000000000000000。2^53 = 9007199254740992。因此,为了迂腐,9e15 仅约等于 2^53(具有两位有效数字)。
@chaiguy 在 9000000000000000 中有 1 个有效数字。在`9007199254740992`中有15位有效数字。
@RoyiNamir 不想在这里开始毫无意义的争论,但 9000000000000000 有 16 个有效数字。如果只需要 1,则必须写为 9x10^15。
@chaiguy 第 9000000000000000 号 - 有 1 SF。其中 90*10^14 有 2. (sigfigscalculator.appspot.com) & mathsfirst.massey.ac.nz/Algebra/Decimals/SigFig.htm(底部)
j
jerome

我这样写:

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;

C
Community

让我们找到源头

描述

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 将评估为真,这在数学上是不正确的。有关详细信息,请参阅 Number.isSafeInteger()。因为 MAX_SAFE_INTEGER 是 Number 的静态属性,所以您始终将其用作 Number.MAX_SAFE_INTEGER,而不是用作您创建的 Number 对象的属性。

浏览器兼容性

https://i.stack.imgur.com/jmCpa.png


M
Marwen Trabelsi

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

但是Bitwise operation are calculated on 32 bits ( 4 bytes ), meaning if you exceed 32bits shifts you will start loosing bits.


这是很重要的一点。这就是为什么我在这里谷歌搜索最大 int 大小。其他答案建议使用 53 位,因此我将其编码为我可以安全地对正值进行按位运算,最高可达 52 位。但它在 31 位之后失败了。谢谢@Marwen
T
Tommy

在 Google Chrome 内置的 javascript 中,你可以到大约 2^1024 之前的数字称为无穷大。


S
SammieFox

斯卡托写道:

您要用于按位运算的任何内容都必须介于 0x80000000(-2147483648 或 -2^31)和 0x7fffffff(2147483647 或 2^31 - 1)之间。控制台会告诉你 0x80000000 等于 +2147483648,但 0x80000000 & 0x80000000 等于 -2147483648

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


P
Peter Mortensen

Firefox 3 似乎没有大量数字的问题。

1e+200 * 1e+100 将计算精细到 1e+300。

Safari似乎也没有问题。 (作为记录,如果其他人决定对此进行测试,则这是在 Mac 上。)

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


它不是 64 位整数,它是 64 位浮点数,其中 52/53 位是整数部分。因此它最多可以处理 1e300,但精度不高。
吉米是正确的。在您的浏览器或 JS 命令行中尝试此操作:100000000000000010 - 1 => 100000000000000020
P
Peter Mortensen

Node.js 和 Google Chrome 似乎都在使用 1024 位浮点值,所以:

Number.MAX_VALUE = 1.7976931348623157e+308

-1:最大可表示(非精确整数)数可能约为 2^1024,但这并不意味着它们偏离了 IEEE-754 64 位标准。
MAX_INT?你的意思是MAX_VALUE?
这是浮点值的最大值。这并不意味着您可以将 int 存储那么长时间
或者更重要的是,您不能可靠地存储一个长不损失准确性的int。 2^53 被称为 MAX_SAFE_INT,因为在该点之上,值变为近似值,与分数相同。