Числа в JavaScript представляют собой двоичные числа с плавающей запятой двойной точности IEEE-754, довольно компактный формат (64 бита), который обеспечивает быстрые вычисления и широкий диапазон. Он делает это, сохраняя число в виде знакового бита, 11-битного показателя степени и 52-битного значащего значения (хотя благодаря умению он фактически получает 53 бита точности). Это двоичная (основание 2) с плавающей запятой: мантисса (плюс некоторая изобретательность) дает нам значение, а экспонента дает нам величину числа.
Естественно, что с таким количеством значащих битов можно сохранить не каждое число. Вот число 1 и следующее по величине число после 1, которое может хранить формат, 1 + 2 -52 ≈ 1.00000000000000022, и следующее по величине число после этого 1 + 2 × 2 -52 ≈ 1.00000000000000044:
+ ------------------------------------------------- -------------- бит знака
/ + ------- + ---------------------------------------- -------------- показатель степени
/ / | + ------------------------------------------------- + - значащее
/ / | / |
0 01111111111 0000000000000000000000000000000000000000000000000000
= 1
0 01111111111 0000000000000000000000000000000000000000000000000001
≈ 1.00000000000000022
0 01111111111 0000000000000000000000000000000000000000000000000010
≈ 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. Вот битовые шаблоны, обратите внимание на самый правый (наименее значимый) бит:
+ ------------------------------------------------- -------------- бит знака
/ + ------- + ---------------------------------------- -------------- показатель степени
/ / | + ------------------------------------------------- + - значащее
/ / | / |
0 10000110011 111111111111111111111111111111111111111111111111
= 9007199254740991 (Число.MAX_SAFE_INTEGER)
0 10000110100 0000000000000000000000000000000000000000000000000000
= 9007199254740992 (Число.MAX_SAFE_INTEGER + 1)
x xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
9007199254740993 (Number.MAX_SAFE_INTEGER + 2) не может быть сохранен
0 10000110100 0000000000000000000000000000000000000000000000000001
= 9007199254740994 (Число.MAX_SAFE_INTEGER + 3)
Помните, что это формат с основанием 2, и с этой экспонентой младший бит больше не является дробным; он имеет значение 2. Оно может быть выключено (9,007,199,254,740,992) или включено (9,007,199,254,740,994); так что на этом этапе мы начали терять точность даже в целочисленной шкале. Что имеет значение для нашего цикла!