Как Lua обрабатывает как целые числа, так и числа с плавающей точкой?

11

Насколько я помню, программируя, меня учили не сравнивать числа с плавающей запятой на равенство. Теперь, читая Программирование на Lua о numberтипе Lua , я обнаружил следующее:

Тип числа представляет действительные числа (числа с плавающей запятой двойной точности). У Lua нет целочисленного типа, так как он не нужен. Существует широко распространенное заблуждение об арифметических ошибках с плавающей запятой, и некоторые люди опасаются, что даже простое приращение может пойти не так с числами с плавающей запятой. Дело в том, что когда вы используете двойное число для представления целого числа, ошибки округления не возникает вообще (если только число не превышает 100 000 000 000 000). В частности, число Lua может представлять любое длинное целое число без проблем округления. Более того, большинство современных процессоров выполняют арифметику с плавающей точкой так же быстро (или даже быстрее), как целочисленная арифметика.

Это правда для всех языков? В принципе, если мы не выйдем за пределы числа с плавающей запятой в двойных числах, мы в целочисленной арифметике безопасны? Или, чтобы лучше соответствовать названию вопроса, есть ли что-то особенное, что Lua делает со своим numberтипом, поэтому он отлично работает как с целочисленным типом, так и с плавающей точкой?

Петр Абдулин
источник
См. Также stackoverflow.com/questions/1848700/…
Joonas Pulakka
@JoonasPulakka спасибо, это очень ценное дополнение.
Петр Абдулин

Ответы:

11

Lua утверждает, что числа с плавающей запятой могут представлять целые числа так же точно, как целочисленные типы, и я склонен согласиться. Там нет точного представления дробной числовой части, чтобы иметь дело с. Независимо от того, храните ли вы целое число в целочисленном типе или храните его в мантиссе с плавающей запятой, результат один и тот же: это целое число может быть представлено точно, если вы не превысите число битов в мантиссе , + 1 бит в показателе степени.

Конечно, если вы попытаетесь сохранить фактическое число с плавающей запятой (например, 12.345) в представлении с плавающей запятой, все ставки выключены, поэтому ваша программа должна четко понимать, что число действительно является целым числом, которое не переполняет мантисса, чтобы относиться к ней как к действительному целому числу (т. е. сравнивать равенство).

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

Дальнейшее чтение
Каково максимальное значение числа в Lua?

Роберт Харви
источник
Как насчет их второго аргумента, то есть, что с плавающей запятой так же быстро или быстрее, чем целочисленная арифметика в современных процессорах? Звучит сомнительно, даже если использовать числа с плавающей запятой для выполнения целочисленной арифметики.
Андрес Ф.
2
@AndresF. Я не понимаю, как это быстрее, если только вы не устраняете приведение, используя один числовой тип вместо двух.
Роберт Харви
Согласовано. Не имеет никакого смысла для меня. Интересно, вырвано ли это из контекста ...
Андрес Ф.
1
Достаточно большие целые числа не могут быть сохранены точно в объекте с плавающей точкой. 64-битный doubleимеет около 51 или около того битов мантиссы; нечетные целые числа больше, чем около 2 ** 51 будут иметь ошибки округления. 64-разрядное целое число может точно хранить большие целочисленные значения, поскольку оно не выделяет биты показателю степени.
Кит Томпсон,
@KeithThompson: я подумал, что это подразумевалось в моем ответе, когда я сказал «хранится в мантиссе». Однако я отредактирую ответ, чтобы уточнить.
Роберт Харви
6

Двойники хранятся как мантисса и показатель степени. Смотрите формат для получения дополнительной информации. В основном все числа имеют вид: мантисса * 2 степени . Для любого целого числа, меньшего, чем 2 52 , показатель степени будет равен нулю, делая бит за битом мантиссу эквивалентной 52-битному целому числу без знака. Отдельный бит знака используется для обозначения отрицательных чисел.

На самом деле, даже некоторые целые числа больше 2 52 могут быть представлены точно, если все цифры после 52- й являются нулями. Кроме того, некоторые дроби, такие как 0,5, могут быть представлены точно. Только когда дробь непрерывно повторяется (например, 1/3) в базе 2 или иным образом требует слишком много битов после радикальной точки, вы теряете точность.

Карл Билефельдт
источник
Это не из-за постоянно повторяющихся десятичных знаков. Это потому, что многие десятичные числа (основание десять) не могут быть представлены в точности как степень двух.
Роберт Харви
3
В базе 2 числа, которые не могут быть представлены точно , будут непрерывно повторяться. Например, 0,1 десятичное число становится 0,0 (0011) в двоичном виде, а 0011 постоянно повторяется.
Карл Билефельдт
3
Да, точно. Но не повторяя в базе 10. Повторяя в базе 2.
Роберт Харви