Перейти к содержимому

Число внутри

Число в mlog одно на всё — дробное двойной точности. Отсюда и предел в 53 бита, и 0.1 + 0.2 ≠ 0.3

Отдельного целого типа в mlog нет. Любое число — дробное двойной точности, то самое double, что и в большинстве языков: 64 бита, из которых 52 отведены под мантиссу, 11 под показатель степени и один под знак.

Из этого устройства следует всё, что дальше: и почему целые точны до определённого предела, и почему 0.1 + 0.2 не равно 0.3, и какие биты переживут упаковку.

тик 0
Операция0
=
Операция1
=
Операция2
=
Операция3
=
Операция4
=
Операция5
=
Операция6
=
Стоп7
@counter0number
сОднойnullnull
безЕдиницыnullnull
проверкаnullnull
дробьnullnull
ошибкаnullnull

Мантисса хранит 52 бита, плюс один подразумеваемый — итого 53 значащих бита. Пока число помещается в них, оно целое и точное; дальше между соседними представимыми числами появляется зазор.

Число Что с ним
до 2⁵³ − 1 хранится точно, бит в бит
2⁵³ = 9 007 199 254 740 992 последнее целое, за которым начинается пропуск
2⁵³ + 1 не существует: округляется обратно к 2⁵³
дальше шаг растёт: сначала через одно, потом через два, четыре…

В примере это видно прямо: сОдной — это 2⁵² с подмешанной единицей, и единица на месте. А безЕдиницы — 2⁵³ с той же единицей, и её там нет: проверка равна нулю, то есть число осталось ровно 2⁵³.

Для битовых операций правило простое:

  • биты 0–52 надёжны. Их можно ставить, читать, сдвигать — число переживёт;
  • биты 53–63 существуют внутри операции, но не в переменной. Игра считает битовые операции в 64-битном целом, а результат кладёт обратно в дробное — и лишнее округляется. Теряются при этом младшие биты: старшие в числе остаются, а точность кончается снизу.
op shl метка 1 52
op or упаковано упаковано метка

Так делать можно. А op shl метка 1 53 уже нет: значение в переменную вернётся, но младшие биты рядом с ним жить не смогут.

Дробное число хранится теми же 53 битами, но уже не «сколько единиц», а «сколько двоичных долей». Десятичная 0.1 в двоичной записи бесконечна — как 1/3 в десятичной, — поэтому хранится ближайшее представимое значение.

В примере дробь равна 0.30000000000000004, а ошибка — разница с настоящей 0.3 — около 5.55 · 10⁻¹⁷.

Бесконечность и NaN в переменную не ложатся

Заголовок раздела «Бесконечность и NaN в переменную не ложатся»

Деление на ноль даёт бесконечность, корень из отрицательного — NaN. Ни то, ни другое переменная не хранит: при записи такое значение превращается в пустоту.

op div плохо 1 0

В плохо окажется null, а не «бесконечность». Поэтому проверка деления на ноль обычно выглядит как проверка на пустоту после операции — или как проверка делителя до неё.

Неофициальный проект, с Anuke не связан. Спрайты, шрифты и переводы Mindustry © Anuke, используются по GPL-3.0; Fira Code — по OFL-1.1. Код сайта — GPL-3.0.