代码之家  ›  专栏  ›  技术社区  ›  Dennis Vash

解析整数[duplicate]后丢失精度

  •  1
  • Dennis Vash  · 技术社区  · 6 年前

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

    0 回复  |  直到 7 年前
        1
  •  884
  •   BobSfougaroudis    4 年前

    JavaScript有两种数字类型: Number BigInt .

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

    这种类型的最大精确积分值是 Number.MAX_SAFE_INTEGER ,即:

    • 2 53
    • 九千六百七十万亿一亿九千九百九十一亿二十五万四千九百九十一

    从这个角度来看:1万亿字节就是1 PB(或1千TB)。

    这里的“安全”是指准确表示整数并正确比较它们的能力。

    From the spec:

    大于2 数量 类型(实际上

    为了安全地使用大于这个的整数,您需要使用 BigInt

    注意,按位运算符和移位运算符对32位整数进行运算,因此在这种情况下,最大安全整数为2 31

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

        2
  •  464
  •   laike9m    5 年前

    >=ES6:

    Number.MIN_SAFE_INTEGER;
    Number.MAX_SAFE_INTEGER;
    

    <

    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
        3
  •  112
  •   Andrew T.    10 年前

    是2 ==9 007 199 254 740 992。这是因为 Number

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

        4
  •  61
  •   Peter Mortensen icecrime    7 年前

    Infinity .

    (Infinity>100)
    => true
    
    // Also worth noting
    Infinity - 1 == Infinity
    => true
    
    Math.pow(2,1024) === Infinity
    => true
    

    对于一些关于这个主题的问题,这可能已经足够了。

        5
  •  41
  •   Sapphire_Brick eapolinario    5 年前

    Jimmy's answer -9007199254740992 包括在内(对不起9007199254740993,你可能认为你是9007199254740993,但你错了! 在下面或里面演示 jsfiddle

    console.log(9007199254740993);

    his answer 这将在28.56年内完成;),所以这里有一个稍微更有效的方法来实现这一点(准确地说,它比28.55999999968312年更有效:)以及 test fiddle :

    /**
     * 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);
        6
  •  32
  •   coolaj86    13 年前

    为了安全

    var MAX_INT = 4294967295;
    

    推理

    我想我应该聪明点,找到 x + 1 === x 用更务实的方法。

    我的机器每秒只能数到1000万。。。所以我会在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);
    }());
    
        7
  •  30
  •   danorton    13 年前

    简而言之,这要视情况而定。

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

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

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

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

    消极的 0!)

        8
  •  29
  •   WaiKit Kung    10 年前

    ECMAScript 6:

    Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
    Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;
    
        9
  •  24
  •   Carr    4 年前

    先前的许多答案都显示了结果 true 属于 9007199254740992 === 9007199254740992 + 1 来验证 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

    用一个简短的版本来演示

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

    在箭头的左边,我们有 位值1 基点 2^52

    所有的位都设置为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)
                                         (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 --| 
    

    现在我们得到了 9007199254740992 ,如果数字大于它,格式可以保存的是 分数的2倍 双精度64位二进制格式 9007199254740992 :

                                (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
    

    中间的数字怎么样[ , 4 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) 所以当数字小于 4503599627370496 (2^52),有一个位可以表示 整数的1/2倍

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

    少于 2251799813685248

    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

    [![在此处输入图像][1]

        10
  •  13
  •   Philippe97    11 年前

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

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

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

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

        11
  •  8
  •   Peter Mortensen icecrime    7 年前

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

        12
  •  6
  •   Peter Mortensen icecrime    7 年前

    尝试:

    maxInt = -1 >>> 1
    

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

        13
  •  6
  •   trincot Jakube    5 年前

    在编写本文时,JavaScript正在接收一个新的数据类型: BigInt . 这是TC39提案 stage 4 EcmaScript 2020 提供Chrome 67+、FireFox 68+、Opera 54和Node 10.4.0版本。它正在狩猎中进行,等等。。。它引入了后缀为“n”的数字字面值,并允许任意精度:

    var a = 123456789012345678901012345678901n;
    

    而且,很明显,由于内存有限,总是会有精度限制,而且在分配必要内存和对如此大的数字执行运算时,也会花费时间。

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

        14
  •  4
  •   Peter Mortensen icecrime    7 年前

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

    javascript: alert(9e15-(9e15+1));
    
        15
  •  3
  •   jerome    10 年前

    我是这样写的:

    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;
    
        16
  •  3
  •   Community CDub    4 年前

    我们到 sources

    这个 MAX_SAFE_INTEGER 常量的值为 9007199254740991 90071999万欧元(254999万欧元)。这个数字背后的原因是JavaScript使用 double-precision floating-point format numbers 如中所述 IEEE 754 只能安全地表示介于 -(2^53 - 1) 2^53 - 1

    这里的Safe指的是准确表示整数并正确比较它们的能力。例如, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 Number.isSafeInteger() 了解更多信息。

    最大安全整数 是的静态属性 Number Number.MAX_SAFE_INTEGER ,而不是作为 数量 您创建的对象。

    enter image description here

        17
  •  0
  •   Tommy    13 年前

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

        19
  •  -1
  •   SammieFox    8 年前

    要用于位操作的任何内容都必须介于 0x80000000(-2147483648或-2^31)和0x7fffffff(2147483647或2^31-

    控制台将告诉您0x80000000等于+2147483648,但是

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

        20
  •  -7
  •   Peter Mortensen icecrime    7 年前

    火狐3在处理大数据方面似乎没有问题。

    野生动物园似乎也没有问题。(作为记录,如果其他人决定测试,这是在Mac上进行的。)

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

        21
  •  -7
  •   Peter Mortensen icecrime    7 年前

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

    Number.MAX_VALUE = 1.7976931348623157e+308