Числа с плавающей запятой полезны для представления чисел, которые
не являются целыми. Диапазон чисел с плавающей запятой такой же, как и
диапазон типа данных C double на используемой вами
машине. На почти всех компьютерах, поддерживаемых Emacs, это формат
плавающей запятой IEEE IEEE binary64, который
стандартизирован в IEEE Std
754-2019 и более подробно обсуждается в статье Дэвида Голдберга
“Что должен знать каждый ученый-компьютерщик о
арифметике с плавающей запятой”. На современных платформах операции с
плавающей запятой в целом соответствуют стандарту IEEE-754; однако результаты
не всегда округляются правильно на некоторых системах, в частности, на
32-битных x86.
На некоторых старых компьютерных системах Emacs может не использовать плавающую запятую IEEE. Мы знаем об одной такой системе, на которой Emacs работает корректно, но не соответствует IEEE-754: это VAX, работающий под NetBSD с GCC 10.4.0, где используется формат VAX ‘D_Floating’. Главные компьютеры, производные от IBM System/370, и их компилятор XL/C также способны использовать формат чисел с плавающей запятой в шестнадцатеричном представлении, но Emacs еще не был собран в такой конфигурации.
Синтаксис чтения чисел с плавающей запятой требует наличия либо десятичной точки, либо экспоненты, либо обоих. Необязательные знаки (‘+’ или ‘-’) предшествуют числу и его экспоненте. Например, ‘1500.0’, ‘+15e2’, ‘15.0e+2’, ‘+1500000e-3’ и ‘.15e4’ — это пять способов записи числа с плавающей запятой, значение которого равно 1500. Все они эквивалентны. Как и Common Lisp, Emacs Lisp требует как минимум одной цифры после десятичной точки в числе с плавающей запятой, у которого нет экспоненты; ‘1500.’ является целым числом, а не числом с плавающей запятой.
Emacs Lisp рассматривает -0.0 как численно равный
обычному нулю при числовых сравнениях, таких как =. Это
соответствует стандарту плавающей запятой IEEE, который
утверждает, что -0.0 и 0.0 численно
равны, даже если другие операции могут их различать.
Стандарт плавающей запятой IEEE поддерживает
положительную и отрицательную бесконечность в качестве значений с плавающей
запятой. Он также предусматривает класс значений, называемых NaN, или
“не число”; числовые функции возвращают такие значения в тех
случаях, когда нет правильного ответа. Например, (/ 0.0 0.0)
возвращает NaN. NaN никогда не равен никакому значению численно, даже
самому себе. NaN несут знак и значащую часть, а нечисловые функции
считают два NaN равными, когда их знаки и значащие части совпадают.
Значащие части NaN зависят от машины, как и цифры в их строковом
представлении.
При работе с NaN и знаками нуля нечисловые функции, такие как
eql, equal, sxhash-eql,
sxhash-equal и gethash, определяют,
являются ли значения неотличимыми, а не численно равными. Например, когда
x и y являются одним и тем же NaN,
(equal x y) возвращает t, тогда как
(= x y) использует численное сравнение и возвращает nil; наоборот, (equal 0.0 -0.0)
возвращает nil, тогда как (= 0.0 -0.0)
возвращает t.
Вот синтаксисы чтения для этих специальных значений с плавающей запятой:
‘1.0e+INF’ и ‘-1.0e+INF’
‘0.0e+NaN’ и ‘-0.0e+NaN’
Бесконечности и NaN недоступны на устаревших системах, в которых отсутствует арифметическая плавающая запятая IEEE. Например, на VAX образца 1980 года Lisp читает ‘1.0e+INF’ как большое, но конечное число с плавающей запятой, а ‘0.0e+NaN’ как другой нечисловой объект Lisp, который вызывает ошибку при численном использовании.
Следующие функции специализированы для работы с числами с плавающей запятой:
Этот предикат возвращает t, если его аргумент с
плавающей запятой является NaN, иначе nil.
Эта функция возвращает ячейку cons (s . e),
где s и e — это соответственно значащая
часть и экспонента числа с плавающей запятой x.
Если x конечно, то s — это число с плавающей запятой в диапазоне от 0.5 (включительно) до 1.0 (исключительно), e — это целое число, и x = s * 2**e. Если x равно нулю или бесконечности, то s равно x. Если x является NaN, то s также является NaN. Если x равно нулю, то e равно 0.
При заданном численном значащем значении s и целом показателе e эта функция возвращает число с плавающей запятой s * 2**e.
Эта функция копирует знак x2 в значение x1 и возвращает результат. x1 и x2 должны быть числами с плавающей запятой.
Эта функция возвращает двоичную экспоненту x. Точнее, если x конечно и не равно нулю, значением является логарифм основанный в 2 от |x|, округленный вниз до целого числа. Если x равно нулю или бесконечности, значением является бесконечность; если x является NaN, значением является NaN.
(logb 10)
⇒ 3
(logb 10.0e20)
⇒ 69
(logb 0)
⇒ -1.0e+INF