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

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

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

oxosxuxt

oxosxuxt1#

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

afdcj2ne

afdcj2ne3#

斯卡托·沃特斯:
要用于位运算的任何内容必须介于0x8000000(-2147483648或-2^31)和0x7fffffff(2147483647或2^31-1)之间。
控制台将告诉您0x8000000等于+2147483648,但0x8000000&0x8000000等于-2147483648
十六进制小数是无符号正值,因此0x8000000=2147483648-这在数学上是正确的。如果要使其成为有符号值,则必须右移:0x8000000>>0=-2147483648。你也可以写1<<31。

new9mtju

new9mtju4#

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

smdncfj3

smdncfj35#

在javascript中,数字的表示是 2^53 - 1 .
然而, Bitwise operation 根据 32 bits ( 4 bytes ) ,这意味着如果超过32位移位,将开始丢失位。

mlmc2os5

mlmc2os56#

让我们回到源头

描述

这个 MAX_SAFE_INTEGER 常量的值为 9007199254740991 (9007199254740991或~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_INTEGER 是数字的静态属性,您总是将其用作 Number.MAX_SAFE_INTEGER ,而不是作为您创建的数字对象的属性。

浏览器兼容性

7fyelxc5

7fyelxc57#

我是这样写的:

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

wmvff8tz8#

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

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

laik7k3q9#

在编写本文时,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)

…但它是有效的。

zbq4xfa0

zbq4xfa010#

尝试:

maxInt = -1 >>> 1

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

qacovj5a

qacovj5a11#

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进行编码是不明确的。

hivapdat

hivapdat12#

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

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

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

3phpmpom

3phpmpom13#

许多早期的答案都表明了这一点 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。

cld4siwp

cld4siwp14#

ecmascript 6:

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

35g0bw7115#

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

相关问题