Добавление к номеру.MAX_VALUE

Ответ на этот вопрос может быть до боли очевиден, но я не могу найти его ни в документах Mozilla, ни в Google при беглом поиске.

Если у вас есть такой код

Number.MAX_VALUE + 1; // Infinity, right?
Number.MIN_VALUE - 1; // -Infinity, right?

Тогда я ожидал бы, что добавление всего к Number.MAX_VALUE подтолкнет его к Infinity. В результате я просто Number.MAX_VALUE плюнул в ответ.

Однако, играя в консоли Chrome JS, я заметил, что на самом деле он не стал Infinity, пока я не добавил/вычел достаточно:

Number.MAX_VALUE + Math.pow(100,1000); // now we hit Infinity
Number.MIN_VALUE - Math.pow(100,1000); // -Infinity at last

Каково объяснение этого «буфера» между Number.MAX_VALUE и Infinity?


person Mark    schedule 31.05.2012    source источник
comment
Есть несколько неинтуитивных вариантов поведения с большими и маленькими числами — например, попробуйте вычесть Number.MIN_VALUE из Number.MAX_VALUE.   -  person kennebec    schedule 31.05.2012
comment
Number.MIN_VALUE — это ближайшее к 0 число, а не самое отрицательное число, которое может представлять JavaScript https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number./MIN_VALUE   -  person Johann Echavarria    schedule 26.04.2014


Ответы (2)


Стандартно...

В ECMAScript сложение двух ненулевых конечных чисел реализовано как (ECMA-262 §11.6.3 Применение аддитивных операторов к числам):

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

Режим округления IEEE-754 к ближайшему указывает, что (атрибуты направления округления IEEE-754 2008 §4.3.1 до ближайшего)

В следующих двух атрибутах направления округления бесконечно точный результат с величиной не менее bemax ( b − ½ b1-p ) округляется до ∞ без изменения знака; здесь emax и p определяются форматом назначения (см. 3.3). С:

  • roundTiesToEven, должно быть доставлено число с плавающей запятой, ближайшее к бесконечно точному результату; если два ближайших числа с плавающей запятой, заключающие в скобки непредставимый бесконечно точный результат, одинаково близки, то должно быть доставлено число с четной младшей значащей цифрой
  • roundTiesToAway должно быть доставлено число с плавающей запятой, ближайшее к бесконечно точному результату; если два ближайших числа с плавающей запятой, заключающие в скобки непредставимый бесконечно точный результат, одинаково близки, то должно быть доставлено число с большей величиной.

ECMAScript не указывает, какое из округлений к ближайшему, но здесь это не имеет значения, потому что оба дают одинаковый результат. Число в ECMAScript двойное, в котором

  • b = 2
  • эмакс = 1023
  • p = 53,

так что результат должен быть не менее 21024 - 2970 ~ 1,7976931348623158 × 10308 для округления. до бесконечности. В противном случае оно будет просто округлено до MAX_VALUE, потому что это ближе, чем Infinity.

Обратите внимание, что MAX_VALUE = 21024 – 2971, поэтому вам нужно добавить как минимум 2971 – 2970. = 2970 ~ 9,979202 × 10291, чтобы получить бесконечность. Мы могли бы проверить:

>>> Number.MAX_VALUE + 9.979201e291
1.7976931348623157e+308
>>> Number.MAX_VALUE + 9.979202e291
Infinity

Между тем, ваше Math.pow(100,1000) ~ 26643,9 значительно превышает 21024 - 2970. Это это уже бесконечность.

person kennytm    schedule 31.05.2012
comment
Отличное объяснение прямо из IEEE-754! Мне нужно найти время, чтобы прочитать эту спецификацию... может быть, когда у меня будут проблемы с засыпанием. - person Mark; 31.05.2012
comment
@Mark: я считаю, что стандарт IEEE 754 краток и удобен в соответствии со стандартами. Чтобы справиться с серьезной бессонницей, я рекомендую вместо этого прочитать стандарт Unicode. :-) - person Mark Dickinson; 31.05.2012
comment
Итак, округление до ближайшего входит ли в него? Я чувствую себя глупо, удаляя свой ответ сейчас. ;-) - person T.J. Crowder; 01.06.2012
comment
@T.J.Crowder: Потому что нет <small>. - person kennytm; 01.06.2012
comment
@kennytm, из вопроса: Number.MIN_VALUE - 1; // -Бесконечность, верно? - правильно ли я понимаю, что это не следует рассматривать как переполнение, это недополнение, и оно должно оцениваться не как -Infinity, а как 0 в соответствии со стандартом IEEE-754? - person Max Koretskyi; 16.10.2016
comment
@Maximus: Number.MIN_VALUE равно 5e-324, это минимальное положительное значение. Результат просто -1. - person kennytm; 16.10.2016

Если вы посмотрите на Number.MAX_VALUE.toString(2), вы увидите, что двоичное представление MAX_VALUE состоит из 53 единиц, за которыми следует 971 ноль. Это связано с тем, что IEEE 754 с плавающей запятой состоит из коэффициента мантиссы, умноженного на степень двойки (поэтому другая половина числа с плавающей запятой является показателем). С MAX_VALUE и мантисса, и экспонента максимальны, поэтому вы видите кучу единиц, сильно сдвинутых по битам.

Короче говоря, вам нужно увеличить MAX_VALUE настолько, чтобы действительно повлиять на мантиссу, иначе ваше дополнительное значение будет потеряно и округлено.

Math.pow(2, 969) — наименьшая степень числа 2, при которой MAX_VALUE не превратится в Infinity.

person apsillers    schedule 31.05.2012
comment
+1, только что указал на это и в моем. На самом деле, я думаю, что это лучший ответ на сегодняшний день. - person T.J. Crowder; 31.05.2012
comment
Спасибо! (Чтобы прояснить для будущих зрителей, @TJ сравнивал со своим собственным (теперь удаленным) ответом, а не с новым ответом Кенни, что довольно хорошо.) - person apsillers; 31.05.2012
comment
+1 за указание точной точки, которая дает советы от MAX_VALUE до Infinity. - person Mark; 31.05.2012