Этот for
цикл когда-нибудь останавливался?
for (var i=0; 1/i > 0; i++) {
}
Если да, то когда и почему? Мне сказали, что это прекратится, но мне не объяснили причины этого.
Обновить
В рамках расследования я написал довольно длинную и подробную статью, в которой объясняется все, что происходит под капотом. Вот что вам нужно знать о типе чисел в JavaScript.
javascript
Макс Корецкий
источник
источник
Number.MAX_SAFE_INTEGER + 1
.Ответы:
(Я не поклонник метаконтента , но ответы : gotnull и le_m правильны и полезны. Они были изначально, а тем более с изменениями, внесенными после публикации этой вики сообщества. Исходная мотивация для этого CW в значительной степени исчез в результате этих изменений, но он остается полезным, поэтому ... Также: Хотя в списке всего пара авторов, многие другие члены сообщества очень помогли, добавив и убрав комментарии. не просто CW по названию.)
Цикл не остановится в правильно реализованном движке JavaScript. (Среда хоста движка может в конечном итоге прекратить его, потому что он бесконечен, но это совсем другое.)
Вот почему:
Первоначально, когда
i
есть0
, условие1/i > 0
истинно, потому что в JavaScript,1/0
естьInfinity
иInfinity > 0
истинно.После этого
i
будет увеличиваться и продолжать расти как положительное целое число в течение длительного времени (следующие 9 007 199 254 740 991 итераций). Во всех этих случаях1/i
они останутся> 0
(хотя значения для1/i
становятся очень маленькими к концу!), И поэтому цикл продолжается до цикла, в которомi
достигается значение, включительноNumber.MAX_SAFE_INTEGER
.Числа в JavaScript представляют собой двоичные числа с плавающей запятой двойной точности IEEE-754, довольно компактный формат (64 бита), который обеспечивает быстрые вычисления и широкий диапазон. Он делает это, сохраняя число в виде знакового бита, 11-битного показателя степени и 52-битного значащего значения (хотя благодаря умению он фактически получает 53 бита точности). Это двоичная (основание 2) с плавающей запятой: мантисса (плюс некоторая изобретательность) дает нам значение, а экспонента дает нам величину числа.
Естественно, что с таким количеством значащих битов можно сохранить не каждое число. Вот число 1 и следующее по величине число после 1, которое может хранить формат, 1 + 2 -52 ≈ 1.00000000000000022, и следующее по величине число после этого 1 + 2 × 2 -52 ≈ 1.00000000000000044:
Обратите внимание на скачок с 1.00000000000000022 до 1.00000000000000044; нет возможности хранить 1.0000000000000003. То же самое может произойти и с целыми числами:
Number.MAX_SAFE_INTEGER
(9,007,199,254,740,991) - это наивысшее положительное целочисленное значение, которое может содержать формат,i
иi + 1
оба они точно представимы ( спецификация ). И 9,007,199,254,740,991, и 9,007,199,254,740,992 могут быть представлены, но следующее целое число, 9,007,199,254,740,993, не может; следующее целое число, которое мы можем представить после 9,007,199,254,740,992, будет 9,007,199,254,740,994. Вот битовые шаблоны, обратите внимание на самый правый (наименее значимый) бит:Помните, что это формат с основанием 2, и с этой экспонентой младший бит больше не является дробным; он имеет значение 2. Оно может быть выключено (9,007,199,254,740,992) или включено (9,007,199,254,740,994); так что на этом этапе мы начали терять точность даже в целочисленной шкале. Что имеет значение для нашего цикла!
После завершения
i = 9,007,199,254,740,992
циклаi++
дает нам ...i = 9,007,199,254,740,992
снова; нет никаких измененийi
, потому что следующее целое число не может быть сохранено, и вычисление заканчивается округлением в меньшую сторону.i
изменилось бы, если бы мы сделалиi += 2
, ноi++
не можем это изменить. Итак, мы достигли устойчивого состояния:i
никогда не меняется и цикл никогда не завершается.Вот различные соответствующие расчеты:
источник
Ответ:
Условие
1/i > 0
всегда будет истинным:Первоначально это правда, потому что
1/0
оцениваетсяInfinity
иInfinity > 0
истинноЭто остается верным, поскольку
1/i > 0
верно для всехi < Infinity
иi++
никогда не достигаетInfinity
.Почему
i++
никогда не доходитInfinity
? Из-за ограниченной точности типаNumber
данных существует значение, для которогоi + 1 == i
:После
i
достижения этого значения (которое соответствует ) оно останется таким же даже после .Number.MAX_SAFE_INTEGER
+ 1
i++
Следовательно, у нас есть бесконечный цикл.
Приложение:
Почему
9007199254740992 + 1 == 9007199254740992
?Тип
Number
данных JavaScript на самом деле представляет собой 64-битное число с плавающей запятой двойной точности IEEE 754 . КаждыйNumber
разбирается и сохраняется в виде трех частей: 1-битный знак, 11-битная экспонента и 52-битная мантисса. Его значение равно -1 знак × мантисса × 2 показатель степени .Каким образом представлен 9007199254740992 ? Как 1.0 × 2 53 или в двоичном формате:
Увеличивая наименьший значащий бит мантиссы, мы получаем следующее большее число:
Значение этого числа 1.00000000000000022… × 2 53 = 9007199254740994.
Что это значит?
Number
может быть 900719925474099 2 или 900719925474099 4 , но ничего между ними.Теперь, какой из них мы выберем для представления 900719925474099 2 + 1 ? В правила округления IEEE 754 дает ответ: 900719925474099 2 .
источник
for (var i = 0; i < Infinity; i += 1E306);
. Но я понимаю, откуда вы идете;)Number.MAX_SAFE_INTEGER
Константа представляет собой максимальное безопасное число в JavaScript.MAX_SAFE_INTEGER
Константа имеет значение9007199254740991
. Причина этого числа заключается в том, что 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
, вы всегда используете его какNumber.MAX_SAFE_INTEGER
, а не как свойствоNumber
созданного вами объекта.ОБНОВИТЬ:
Кто-то в удаленном ответе упомянул:
i
никогда не достигнет бесконечности. Как только он достигнетNumber.MAX_SAFE_INTEGER
,i++
переменная больше не будет увеличиваться. На самом деле это не так .@TJ Crowder комментирует то
i = Number.MAX_SAFE_INTEGER; i++; i == Number.MAX_SAFE_INTEGER;
естьfalse
. Но следующая итерация достигает неизменного состояния, поэтому ответ в основном правильный.i
в примере никогда не доходитInfinity
.источник
9007199254740992 + 1
есть9007199254740992
.for (var i=0; NaN > 0; i++) { console.log(i); }
ничего не будет производить.1/i > 0
) будет ложным, поскольку ifi
есть0
,1/i
естьNaN
иNaN > 0
ложно.