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

inn6fuwd  于 2021-09-13  发布在  Java
关注(0)|答案(20)|浏览(459)

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

qacovj5a

qacovj5a1#

javascript有两种数字类型: NumberBigInt .
最常用的数字类型, Number ,是一个64位浮点ieee 754数字。
此类型的最大精确整数值为 Number.MAX_SAFE_INTEGER ,即:
253-1,或
+/-9007199254740991,或
玖亿肆仟柒万亿壹仟玖佰玖拾玖亿贰仟伍佰肆拾肆万柒仟玖佰玖拾壹
从这个Angular 来看:1万亿字节等于1 PB(或1000 TB)。
在此上下文中,“安全”指的是准确表示整数并正确比较它们的能力。
根据规范:
请注意,大小不大于253的所有正整数和负整数都可以表示为 Number 类型(实际上,整数0有两种表示形式,+0和-0)。
要安全地使用大于此值的整数,需要使用 BigInt ,它没有上限。
请注意,按位运算符和移位运算符对32位整数进行运算,因此在这种情况下,最大安全整数为231-1或2147483647。

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

关于编号9007199254740992的主题的技术说明:该值有一个精确的ieee-754表示,您可以从变量中分配和读取该值,因此对于小于或等于该值的整数域中非常仔细选择的应用程序,您可以将其视为最大值。
在一般情况下,必须将此ieee-754值视为不精确值,因为它对逻辑值9007199254740992或9007199254740993进行编码是不明确的。

nbewdwxp

nbewdwxp2#

=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
55ooxyrt

55ooxyrt3#

它是253==9 007 199 254 740 992。这是因为 Number s以浮点形式存储在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

643ylb08

643ylb084#

在javascript中,有一个数字叫做 Infinity .
示例:

(Infinity>100)
=> true

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

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

这可能足以回答有关此主题的一些问题。

3xiyfsfu

3xiyfsfu5#

jimmy的答案正确地表示连续javascript整数范围为-9007199254740992到9007199254740992(抱歉9007199254740993,您可能认为您是9007199254740993,但您错了!下面的演示或在jsfiddle中的演示)。

console.log(9007199254740993);

然而,没有一个答案能在程序上找到/证明这一点(除了coolaj86在其答案中提到的将在28.56年内完成的答案;),因此,这里有一种更有效的方法(准确地说,它的效率提高了28.559999968312年:),还有一把测试小提琴:

/**
 * 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);
k5hmc34c

k5hmc34c6#

为了安全

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

35g0bw717#

简单的回答是“视情况而定”
如果您在任何位置使用位运算符(或如果您指的是数组的长度),则范围为:
未签名: 0…(-1>>>0) 签署: (-(-1>>>1)-1)…(-1>>>1) (按位运算符和数组的最大长度限制为32位整数。)
如果不使用位运算符或不使用数组长度:
签署: (-Math.pow(2,53))…(+Math.pow(2,53)) 这些限制是由“数字”类型的内部表示施加的,该类型通常对应于ieee 754双精度浮点表示(请注意,与典型的有符号整数不同,由于内部表示的特性,负极限的大小与正极限的大小相同,内部表示实际上包括负0!)

cld4siwp

cld4siwp8#

ecmascript 6:

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

3phpmpom9#

许多早期的答案都表明了这一点 9007199254740992 === 9007199254740992 + 1 为true,以验证9007199254740991是最大且安全的整数。
但如果我们继续做积累会怎么样:

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

我们可以发现,在大于9007199254740992的数字中,只有偶数是可表示的。
这是解释双精度64位二进制格式如何工作的入口。让我们看看如何使用此二进制格式保存(表示)9007199254740992。
使用简短版本从4503599627370496进行演示:

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

在箭头的左侧,我们有位值1和一个相邻的基点。通过使用左侧的指数部分,将基点向右移动52步。小数点在末尾,我们得到纯二进制的4503599627370496。
现在让我们继续用1递增分数部分,直到所有位都设置为1,这等于十进制中的9007199254740991。

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 --|

现在我们得到9007199254740992,对于大于它的数字,该格式只能处理2的增量,因为分数部分的每一个增量1都会乘以指数部分的左2。这就是当奇数大于9007199254740992时,双精度64位二进制格式无法保存奇数的原因:

(consume 2^52 to move radix point to the end)
  1 . 0000 ---- 0001  *  2^53  =>  1  0000 ---- 0001.  *  2
     |-- 52 bits --|                 |-- 52 bits --|

按照此模式,当数字大于9007199254740992*2=18014398509481984时,只能保留分数的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

[2251799813 685 248,4503 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),因此当数字小于4503599627370496(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
/**
   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。

hivapdat

hivapdat10#

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

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

在chrome 30中,在不到一毫秒的时间内,我得到了9007199254740992。
它将测试2的幂,以确定当“加”1时,哪一个等于他自己。

oxosxuxt

oxosxuxt11#

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

zbq4xfa0

zbq4xfa012#

尝试:

maxInt = -1 >>> 1

在Firefox3.6中是2^31-1。

laik7k3q

laik7k3q13#

在编写本文时,javascript正在接收一种新的数据类型: BigInt . 这是第4阶段的tc39提案,将包含在ecmascript 2020中。 BigInt 在Chrome67+、Firefox68+、Opera54和Node10.4.0中提供。它正在safari等地进行。。。它引入了具有“n”后缀的数字文字,并允许任意精度:

var a = 123456789012345678901012345678901n;

当然,当这样的数字(可能是无意中)被强制为数字数据类型时,精度仍然会丢失。
而且,很明显,由于内存有限,总是存在精度限制,分配必要的内存和对如此大的数字执行算术需要花费大量的时间。
例如,生成具有十万位十进制数字的数字在完成之前需要明显的延迟:

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

…但它是有效的。

wmvff8tz

wmvff8tz14#

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

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

7fyelxc515#

我是这样写的:

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;

相关问题