Какое наибольшее целочисленное значение в JavaScript может быть достигнуто числом без потери точности? - PullRequest
894 голосов
/ 21 ноября 2008

Это определяется языком? Есть ли определенный максимум? Отличается ли он в разных браузерах?

Ответы [ 24 ]

817 голосов
/ 21 ноября 2008

+ / - 9007199254740991

ECMA Раздел 8.5 - Номера

Обратите внимание, что все положительные и отрицательные целые числа, величина которых не превышает 2 53 , представимы в типе Number (действительно, целое число 0 имеет два представления: +0 и -0).

Это 64-битные значения с плавающей запятой, наибольшее точное целое значение равно 2 53 -1 или 9007199254740991. В ES6 это определяется как Number.MAX_SAFE_INTEGER .

Обратите внимание, что побитовые операторы и операторы сдвига работают с 32-разрядными целыми числами, поэтому в этом случае максимальное безопасное целое число равно 2 31 -1 или 2147483647.


Проверьте это!
var x = 9007199254740992;
var y = -x;
x == x + 1; // true !
y == y - 1; // also true !
// Arithmetic operators work, but bitwise/shifts only operate on int32:
x / 2;      // 4503599627370496
x >> 1;     // 0
x | 1;      // 1

Техническое примечание по теме номера 9007199254740992: Существует точное представление этого значения в IEEE-754, и вы можете присвоить и прочитать это значение из переменной, поэтому для очень осторожно выбранные приложения в область целых чисел меньше или равна этому значению, вы можете рассматривать это как максимальное значение.

В общем случае вы должны рассматривать это значение IEEE-754 как неточное, поскольку неясно, кодирует ли оно логическое значение 9007199254740992 или 9007199254740993.

442 голосов
/ 21 ноября 2008

> = ES6:

Number.MIN_SAFE_INTEGER;
Number.MAX_SAFE_INTEGER;

<= ES5 </strong>

С ссылка :

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
107 голосов
/ 07 декабря 2010

Это 2 53 == 9 007 199 254 740 992. Это потому, что Number s хранятся в виде 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

53 голосов
/ 21 января 2012

В JavaScript есть число, называемое Infinity.

Примеры:

(Infinity>100)
=> true

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

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

Этого может быть достаточно для некоторых вопросов по этой теме.

40 голосов
/ 25 июля 2012

Ответ Джимми правильно представляет непрерывный целочисленный спектр JavaScript как -9007199254740992 до 9007199254740992 включительно (извините, 9007199254740993, вы можете подумать, что вы 9007199254740993, но вы неправильно! Демонстрация ниже или в jsfiddle ).

document.write(9007199254740993);

Однако, нет ответа, который находит / доказывает это программно (кроме того, на который CoolAJ86 ссылается в его ответ , который закончится через 28,56 лет;), так что здесь есть немного более эффективный способ сделать что (если быть точным, он более эффективен примерно на 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);
32 голосов
/ 24 августа 2011

На всякий случай

var MAX_INT = 4294967295;

Рассуждения

Я думал, что буду умнее и найду значение, при котором x + 1 === x с более прагматичным подходом.

Моя машина может считать только 10 миллионов в секунду или около того ... поэтому я отправлю ответ с окончательным ответом через 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);
}());
28 голосов
/ 31 марта 2014

ECMAScript 6:

Number.MAX_SAFE_INTEGER = Math.pow(2, 53)-1;
Number.MIN_SAFE_INTEGER = -Number.MAX_SAFE_INTEGER;
27 голосов
/ 17 июля 2011

Короткий ответ: «Это зависит».

Если вы где-либо используете побитовые операторы (или если вы ссылаетесь на длину массива), диапазоны:

без знака: 0…(-1>>>0)

Подпись: (-(-1>>>1)-1)…(-1>>>1)

(Случается, что побитовые операторы и максимальная длина массива ограничены 32-разрядными целыми числами.)

Если вы не используете побитовые операторы или не работаете с длинами массива:

Подпись: (-Math.pow(2,53))…(+Math.pow(2,53))

Эти ограничения накладываются внутренним представлением типа «Число», которое обычно соответствует представлению с плавающей точкой двойной точности IEEE 754. (Обратите внимание, что в отличие от типичных целых чисел со знаком, величина отрицательного предела совпадает с величиной положительного предела из-за характеристик внутреннего представления, которое фактически включает отрицательное 0!)

13 голосов
/ 11 марта 2018

Многие ответы ранее показывают результат true из 9007199254740992 === 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 хранится (представляется) с использованием этого двоичного формата.

Мы начинаем с 4 503 599 627 370 496 с первой краткой версией формата:

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

На стороне перед стрелкой у нас есть битовое значение 1 и смежная осевая точка , затем, умножив 2^52, мы вправо переместим основную точку 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)
                                     (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 992 , и с числом, большим его, формат может содержать 2 раза от дроби :

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

Значение бита 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

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

enter image description here

Таким образом, чтобы сделать экспоненту 2 ^ 52, нам точно нужно установить e = 1075.

11 голосов
/ 05 октября 2013

Другие, возможно, уже дали общий ответ, но я подумал, что было бы неплохо дать быстрый способ его определения:

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

Что дает мне 9007199254740992 менее чем за миллисекунду в Chrome 30.

Он проверит степень 2, чтобы определить, какая из них, когда «добавлено» 1, равна себе.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...