Подтвердить что ты не робот

Добавление в Number.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?

4b9b3361

Ответ 1

Standardwise...

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

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

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

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

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

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

  • b = 2
  • emax = 1023
  • p = 53,

поэтому результат должен быть не менее 2 1024 - 2 970 ~ 1.797693134862315 8 × 10 308 в чтобы округлить до бесконечности. В противном случае он будет округлен до MAX_VALUE, потому что это ближе, чем бесконечность.

Обратите внимание, что MAX_VALUE = 2 1024 - 2 971 поэтому вам нужно добавить не менее 2 971 - 2 970= 2 970 ~ 9.979202 × 10 291 чтобы получить бесконечность. Мы могли бы проверить:

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

Между тем, ваш Math.pow(100,1000) ~ 2 6643.9 намного превосходит 2 1024 - 2 970. Это уже бесконечность.

Ответ 2

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

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

Math.pow(2, 969) - самая низкая степень 2, которая не будет опрокидывать MAX_VALUE на Infinity.