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


11

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

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

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



@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.
— Роберт Харви
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.