Международный стандарт представления чисел с плавающей точкой в ЭВМ

Материал из MachineLearning.

Перейти к: навигация, поиск

Содержание

Введение

Практически любой язык программирования даёт возможность использовать в вычислениях дробные числа. Когда дело касается программной реализации численных методов или любых других вычислений на ЭВМ, важным вопросом является внутреннее представление чисел, с которым приходится работать программисту. От этого главным образом зависит точность вычислений,а также их скорость.

В этом отчёте будут рассматриваться те аспекты представления чисел в ЭВМ, которые важны пользователям, желающим активно работать с дробными величинами. Вначале будут введены общепринятые понятия для дальнейшего изложения материала. Будет достаточно подробно рассмотрен наиболее часто используемый стандарт IEEE 754. В заключение будут приведены способы доступа к основным параметрам представления дробных чисел в ряде языков программирования (C,C++,Fortran,Pascal).

Числа с плавающей точкой

Числа с плавающей точкой - общепринятая форма представления дробных чисел в ЭВМ. Основными параметрами такой формы представления является основание степени \beta (base) и точность p (precision). При этом всегда требуется, чтобы основание степени было целым чётным числом. Если $\beta=10$ и $p=3$, то число 0.1 представляется в виде $1.00\times 10^{-1}$. Однако, очевидно, что при определённых параметрах некоторые числа не удастся представить точно. Например, при $\beta=2$ и $p=24$ то же самое число 0.1 представляется приблизительно в виде 1.10011001100110011001101\times 2^{-4} (поскольку в бинарном представлении число 0.1 имеет бесконечный вид).

В общем случае при заданных параметрах запись вида $d_0.d_1d_2 \dots d_{p-1}\times\beta^e$ представляет число

$\pm\left(d_0+d_1\beta^{-1}+d_2\beta^{-2}\dots+d_{p-1}\beta^{p-1}\right)\beta^e,\ ( 0\leq d_i<\beta )$

При этом d_0.d_1d_2 \dots d_{p-1} называется мантиссой числа и состоит из p позиций. В дальнейшем под числом с плавающей точкой мы будем понимать дробные числа точно представимые в смысле данной формы.

Существуют ещё два важных параметра — максимальный и минимальный показатели степени $e_{max}$ и e_{min}. Таким образом, при фиксированных параметрах мы можем представить $2\left(e_{max}-e_{min}+1\right)\beta^p$ разных чисел с учётом знака.

Здесь возникает проблема - что делать с числами, не представимыми точно. Чаще всего такая ситуация возникает при попытке представить числа, имеющие слишком длинное или вообще бесконечное представление (пример с 0.1). В этом случае нужное нам число лежит где-то между двумя числами с плавающей точкой и будет представляться одним из них. Реже встречается попытка использовать числа, меньшие чем 1.0\times\beta^{e_{min}}, или большие чем \beta.0\times\beta^{e_{max}}. Подробнее об этих случаях речь пойдёт в разделе "Стандарт IEEE".

Введём ещё одну договорённость. Пока что представление чисел с плавающей точкой неуникально. Например, при $\beta=10$ и $p=3$ число 0.1 можно представить как 0.01\times 10^{1} и как 1.00\times 10^{-1}. Представление числа, в старшей позиции которого стоит цифра, отличная от нуля \left(d_0\neq 0\right), мы будем называть нормализованным. Использование нормализованных форм решает проблему неединственности представления чисел с плавающей точкой. (Однако, при такой договорённости возникает интересный вопрос — как представлять 0?)

Машинный эпсилон

Как известно, существует 2 вида погрешностей вычисления — абсолютная и относительная (Ошибки вычислений). Под относительной погреностью понимается отношение

\delta(\tilde a)=\frac{|\tilde a-a|}{a},

где \tilde a – значение, полученное при округлении, а a - точное значение вычислений.

Представим, что результатом округления действительного числа стало число $d.dd\dots d\times\beta^e$. Худшему случаю округления соответствует абсолютная погрещность, равная $0.00 \dots 0\beta'\times\beta^e$, где \beta'=\beta/2. В мантиссе результата округления p позиций , в мантиссе абсолютной погрешности p+1 позиция.

При попытке написать неравенство для относительной погрешности, соответствующей упомянутой выше абсолютной погрешности, несложно получить, что

\left(1/2\right)\beta^{-p}\leq\delta\leq\left(\beta/2\right)\beta^{-p}.

Величину \eps=\left(\beta/2\right)\beta^{-p} принято называть машинным эпсилоном (machine epsilon). Таким образом можно утверждать, что при округлении дробного числа ближайшим к нему числом с плавающей точкой относительная погрешность округления не превосходит машинного эпсилона.

Существует и другое определение. Машинный эпсилон можно определить как минимальное положительное число, которое будучи прибавлено к единице даёт результат отличный от единицы. Читателю предлагается проверить эквивалентность этих определений самостоятельно.

Стандарт IEEE

Существует два разных стандарта IEEE для чисел с плавающей точкой. IEEE 754 - двоичный стандарт и требует, чтобы \beta=2, а p=24 для одинарной точности (single) и p=53 для двойной точности (double). Также в стандарте IEEE 754 точно обговорено использование битов при представлении чисел в одинарной и двойной точностях. В стандарте IEEE 854 \beta может принимать значение 10 или 2. Также ничего не говорится о распределении битов между мантиссой и степенью.

Понятие стандарт IEEE используется для обозначения свойств, присущих обоим из перечисленных стандартов.

Основание степени

Выбор в качестве основания степени 10 не требует особых разъяснений. Десятичная система - система, привычная для человека. В случае двоичной системы стоит обсудить некоторые достоинства, присущие ей. Мы договорились использовать нормализованные формы чисел. Если \beta=2, то в старшей позиции может стоять только 1. Это даёт нам возможность не хранить эту единицу в памяти и тем самым получить дополнительный бит для мантиссы. В этом случае принято говорить, что стандарт использует скрытый бит (hidden bit).

Вернёмся к вопросу о представлении нуля в нормализованной форме. Ноль соответствует нулевой мантиссе и степени e_{min}-1. Таким образом ноль представляется в виде 1.0\times 2^{e_{min}-1}.

Точность представления

Стандарт IEEE предлагает 4 разных точности: одинарныя (single), двойная (double), одинарная расширенная (single-extended) и двойная расширенная (double-extended). IEEE 754 жёстко обговривают число бит одинарной и двойной точности. Это означает, что на всех ЭВМ, поддерживающих IEEE 754, количество бит в представлении чисел с одинарной точностью и с двойной точностью фиксированы. Количество бит расширенных точностей жёстко не фиксируется. Расширенные форматы призваны хоть немного увеличить количество бит на мантиссу и на показатель степени. Ниже представлена таблица параметров различных точностей в стандарте IEEE.

Форматы
Параметры Формат
Single Single-extended Double Double-extended
p 24 32 53 64
e_{max} +127 1023 +1023 >16383
e_{min} -126 \leq-1022 -1022 \leq-16382
Показатель степени 8 бит \leq 11 бит 11 бит 15 бит
Длинна записи 32 бит 43 бит 64 бит 79 бит

Показатель степени

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

Существует несколько общепринятых методов. Например, резервировать один бит на знак, как это реализовано в представлении мантиссы. Однако IEEE использует другой метод - метод со смещением. Для одинарного и двойного формата вводятся смещения - 127 и 1023 соответственно. Допустим, k - значение бинарного вида показателя экспоненты в смысле беззнаковой величины. Тогда показатель экспоненты определяется как k-127 для одинарной точности и как k-1023 для двойной.

Из таблицы следует, что для одинарного формата e_{min}=-126 и e_{max}=127. Может возникнуть вопрос: почему \left|e_{min}\right|<\left|e_{max}\right|? Это сделано для того, чтобы величина обратная к минимальному по модулю числу \left(1/2^{e_{min}}\right) не выходила за рамки представимости. (Однако, при этом величина обратная к максимальному числу становится гарантированно меньше минимального представимого числа. Дело в том, что переполнение - куда более серьёзная проблема, чем потеря значимости.)

В 8 бит, выделенные на показатель степени в одинарном формате, уместится 256 различных значений (от 0 до 255). Это соответствует диапазону показателей степени от -127 до 128. Зачем используется показатель -127 (e_{min}-1) мы уже знаем. Об использовании значения 128 (e_{max}+1) речь пойдёт в разделе "Специальные величины".

Операции

Стандарт IEEE требует, чтобы результаты основных арифметических операций — умножения, сложения, вычетания и деления — были точно округлены (exactly rounded). Это означает, что сначала должен быть вычислен точный ответ, а потом он должен быть округлён до ближайшего числа с плавающей точкой.

Поговорим немного об округлении. Само понятие окрунление на самом деле прозрачно — за исключением округления чисел вида 12.5. К какому из чисел 12 и 13 его округлить? Существует два различных подхода к этому вопросу. Первый - разделить множество {0,1,2,3,4,5,6,7,8,9} пополам на {0,1,2,3,4} и {5,6,7,8,9} и первое округлять вниз, а второе — наверх. Второй подход — округлять числа так, чтобы в наименее значащей позиции после округления стояло чётное число. Например, 12.5 округлять в 12, а 10.1235 — в 10.124. Такое округление называется чётным.

В стандарте IEEE используется чётное округление.

Также стандарт IEEE вводит гарантии касательно дополнительных операций - извлечения квадратного корня, взятия остатка от деления и перевода целых чисел (integer) в числа с плавающей точкой (и наоборот). Результаты этих операций должны быть также точно округлены. В отличие от этих операций нет никаких гарантий по поводу перевода между десятичным и двоичным представлениями. Дело в том, что существуют достаточно эффективные алгоритмы округления всех операций, кроме операции перевода из десятичной формы в двоичную.

Ещё одним интересным вопросом является округление значений трансцендентных функций (Функций, которые не могут быть выражены конечным числом суперпозиций стандартных арифметических операций). Стандарт IEEE не гарантирует точного округления значений таких функций. Хорошим примером является округление значений экспоненты. \exp(1.626)=5.0835. К какому значению округлять \exp(1.626) — к 5.083 или к 5.084? Для округления сначала надо получить точное значение функции. При увеличении точности \exp(1.626)=5.08350, затем \exp(1.626)=5.083500, затем \exp(1.626)=5.0835000. Для принятия решения нам нужно определить чему из 5.0835000\dots 00d или 5.0834999\dots 999d равна \exp(1.626). Понятно, что в случае экспоненты мы не гарантированно доберёмся до интересующей нас позиции. Поэтому в случае трансцендентных функций нет смысла требовать, чтобы значение было сначала получено с бесконечной точностью и затем округлено.


Специальные значения

Представим, что у нас есть программа. При работе эта программа в какой-то момент пытается извлечь корень из -4. Если бы в стандарте не было никаких резервированных значений и все битовые последовательности выражали бы соответствующие им числа, то не было бы выхода лучше, чем остановить работу программы с сообщением об ошибке.

В стандарте IEEE существуют в некотором смысле резервированные последовательности бит. В их число входят: бесконечность, NaN, ненормализованные числа и ноль со знаком.

В таблице ниже приведены представления этих специальных значений в стандарте IEEE.

Специальные значения
Показатель степени Дробная часть мантиссы Обозначение
e=e_{min}-1 f=0 \pm 0
e=e_{min}-1 f\neq 0 0.f\times2^{e_{min}}
e_{min}\leq e\leq e_{max} 1.f\times2^e
e=e_{max}+1 f=0 Inf
e=e_{max}+1 f\neq0 NaN

NaN

NaN (Not a number) используется стандартом IEEE для обработки ситуаций вида извлечения корня из отрицательного числа.

Приведём хороший пример, демонстрирующий важность этого специального значения. Предположим, что у нас есть программа, вычисляющая нули функции. Мы хотим реализовать её так, чтобы она не трабовала интервал поиска в качестве входного аргумента. Такая реализация может вызвать проблему — что, если программа попытается вычислить значение функции вне области её определения? В частности, программа может попытаться взять квадратный корень от -4. Если бы программа выдала сообщение об ошибке и остановила свою работу она была бы для нас бесполезна. Существование NaN даёт нам возможность вернуть его в качетсве результата взятия квадратного корня и продолжить работу.

Приведём небольшую таблицу, демонстрирующую случаи возвращения NaN.

Операции, возвращающие NaN
Операция Случай, когда возникает NaN
+ Inf + \left(-Inf\right)
\times 0\times Inf
/ 0/0, Inf/Inf
REM x REM 0,\ Inf REM y
\sqrt{x} \sqrt{x}\ \left(x<0\right)

В битовом представлении NaN не оговаривается, какое значение должна принимать мантисса. Единственное ограничение — она не должна быть нулевой. Этот факт используется для передачи определённой системной информации через мантиссу. Таким образом существует много различных значений вида NaN — каждое для своего случая.

Предположим, что мы вычисляем значение некоторого выражения, например \left(a+b+c\right)/d. Допустим, a принимает значение NaN. В этом случае итоговое значение выражения также равно NaN. Если рассматривается некоторое длинное выражение, в ходе вычисления которого возникает значение NaN, то системная информация в мантиссе должна соответствовать тому значению NaN, которое возникло первым. Исключением является, например, сложение двух NaN. В этом случае мантисса будет соответствовать одному из них, не обязательно первому.

Бесконечность

Ноль со знаком

Ненормализованные числа

Доступ к параметрам представления чисел с плавающей точкой в различных языках программирования

Список литературы

  • David Goldberg.  What Every Computer Scientist Should Know About Floating-Point Arithmetic. ACM Computing Surveys, Vol. 23, No. 1 (March 1991), pages 5--48.


Личные инструменты