Арифметика с плавающей точкой не может выполнять все операции точно для всех операндов. Когда результат не представим как переменная с плавающей точкой, неизбежна аппроксимация. Для того, чтобы оставить аппроксимацию математически управляемой, аппаратная часть подчиняется стандартам точности, которые могут моделироваться конкретными неравенствами вместо уравнений. Давайте предположим, что
X <- Y @ Z (где @ - некоторая операция)
представляет типичную операцию. При изначальном режиме округления (округление до ближайшего), каждая операция выполняется с абсолютной ошибкой не более чем половина разности между двумя числами с плавающей точкой ближайшими к точным результатам. Пусть x является значением, хранимым в переменной с именем X в программе, y - переменной Y и z - переменной Z. Обычно y и z будут отличаться суммарной ошибкой от желаемого результата и от того, что было бы получено при отсутствии ошибок. Для вычисления x мы предполагаем, что y и z яляются наилучшей аппроксимацией и что мы будем вычислять x настолько, насколько это возможно. Если выражение y@z представимо точно, то мы ожидаем, что x=y@z, и это то, что мы получили для каждой алгебраической операции на устройстве обработки операций с плавающей точкой процессора i486 (то есть, когда выражение y@z является одним из y+z, y-z, y*z, y/z, sqrt z). Но если выражение y@z должно быть аппроксимировано, как обычно, то x должен отличаться от y@z не более чем на половину разности между двумя представимыми числами, которые покрывают выражение y@z. Эта разность зависит от двух факторов:
Как определена точность, с которой проводятся вычисления, либо битами управления точностью, либо форматом, используемым в памяти. На процессоре i486 точность бывает простая (24 значащие бита), двойная (53 значащих бита) и расширенная (64 значащих бита).
Как близко значение выражения y@z к нулю. В этом отношении существование денормальных чисел на процессоре i486 предоставляет определенное преимущество над системами, которые не допускают денормальные числа.
В любых системах чисел с плавающей точкой плотность представимых чисел больше ближе к нулю, чем ближе к наибольшим представимым величинам. Однако, машины, которые не используют денормальные числа, страдают от огромной дыры между нулем и его ближайшими соседями. На Рисунках 16-1 и 16-2 показано, что случается около нуля в двух различных системах чисел с плавающей точкой.
На Рисунке 16-1 показана система чисел с плавающей точкой, которая (подобно процессору i486) допускает денормальные числа. Для упрощения показаны только неотрицательные числа и рисунок иллюстрирует систему чисел, которая несет только четыре значащие разряда вместо 24-х, 53-х или 64-х значащих разряда, которые предлагает процессор i486.
Каждый плюс обозначает представимое четырьмя значащими битами число, а длинная вертикальная черта обозначает степень 2. Минусы обозначают числа, не представимые с этой точностью. Денормальные числа лежат между 0 и ближайшей нормальной степенью 2. Они не менее плотны чем оставшиеся ненулевые числа.
+---------------------------------------------------------------+| || 0+++++++|+++++++|-+-+-+-+-+-+-+-|---+---+---+---+---+---+.... || || +-------+ - - - - - - Нормальные числа - - - - - -> || Денормальные || числа || |+---------------------------------------------------------------+Рисунок 16-1. Система Чисел с Плавающей Точкой с Денормальными Значениями +---------------------------------------------------------------+| || || 0 |+++++++|-+-+-+-+-+-+-+-|---+---+---+---+---+---+.... || || + - - - - - - Нормальные числа - - - - - -> || || || |+---------------------------------------------------------------+Рисунок 16-2. Система Чисел с Плавающей Точкой без Денормальных Значений
На Рисунке 16-2 показана система чисел с плавающей точкой, которая (в отличие от модуля обработки операций с плавающей точкой процессора i486 или сопроцессора 387) не допускает денормальные числа. Существует две большие дырки: одна на положительной стороне от нуля (как показано), а другая на отрицательной стороне от нуля (не показано). Пространство между нулем и ближайшим соседом нуля отличается от пространства между этим соседом и следующим большим числом с коэффициентом примерно 8.4 x 10**(6) для простого формата, 4.5 x 10**(15) для двойного формата и 9.2 x 10**(18) для расширенного формата. Эти дырки усложняют анализ ошибок.
Преимущество денормальных чисел бесспорно, при рассмотрении того, что происходит в случае, когда маскируется исключение отрицательного переполнения и значение выражения y@z попадает в пространство между нулем и наименьшим нормальным значением. Процессор i486 выдает ближайшее денормальное число. Этот процесс может быть назван "последовательное отрицательное переполнение". Действие не отличается от округления, которое может случиться, когда значение выражения y@z попадает в нормальный диапазон.
С другой стороны, система, которая не имеет денормальных чисел, возвращает как результат ноль - процесс, который может быть намного более неточен, чем округление. Это действие может быть названо "резкое переполнение". Модуль обработки операций с плавающей точкой процессора i486 и математический сопроцессор 387 обрабатывают денормальные значения по другому, иначе, чем математические сопроцессоры 8087/80287. Для детального знакомства обратитесь к разделу 16.2.4.
Нули
Значение нуль в десятичном вещественном или целочисленном формате может быть со знаком плюс или минус, тогда как знак двоичного целого нуля всегда положительный. При вычислениях значение нуля всегда ведет себя одинаково, несмотря на знак, и обычно то, что ноль может быть со знаком, является очевидным для программиста. При необходимости можно использовать команду FXAM для того, чтобы определить знак нуля.
Либо программист может закодировать ноль, или он может быть создан модулем обработки операций с плавающей точкой как маскируемый ответ на исключение отрицательного переполнения. Если ноль загружен или сгенерирован в регистре, то этот регистр помечается как ноль. В Таблице 16-3 приведены результаты команд, выполненных с нулевыми операндами, а также показано, как может получиться ноль из ненулевых операндов.
Таблица 16-3. Нулевые Операнды и Результаты +---------------------------------------------------------------+| Команда | Операнды | Результат |+------------------+--------------------+-----------------------|| FLD,FBLD | ё0 | *0 || FILD | +0 | +0 || FST,FSTP,FRNDINT | ё0 | *0 || | +X | +0(1) || | -X | -0(1) || FBSTP | ё0 | *0 || FIST,FISTP | ё0 | *0 || | +X | +0(3) || | -X | -0(4) || FCHS | +0 | -0 || | -0 | +0 || FABS | ё0 | +0 || Сложение | +0 плюс +0 | +0 || | -0 плюс -0 | -0 || | +0плюс-0, -0плюс+0 | ё0(2) || | -Xплюс+X, +Xплюс-X | ё0(2) || | ё0плюсёX, ёXплюсё0 | #X || Вычитание | +0 минус -0 | +0 || | -0 минус +0 | -0 || | +0 минус+0,-0 минус| ё0(2) || | -0 | ё0(2) || | +X минус+X,-X минус| -#X || | -X | #X || | ё0 минус ёX | || | ёX минус ё0 | || Умножение | ё0 x ё0 | (+)0 || | ё0 x ёX, ёX x ё0 | (+)0 || | +X x +Y, -X x -Y | +0(1) || | +X x -Y, -X x +Y | -0(1) || Деление | ё0 / ё0 | Недопустимая Операция || | ёX / ё0 | (+)oo (Деление на 0) || | ёX / ёoo | (+)0 || | +0 / +X, -0 / -X | +0 || | +0 / -X, -0 / +X | -0 || | -X / -Y, +X / +Y | +0(1) || | -X / +Y, +X / -Y | -0(1) || FPREM, FPREM1 | ё0 rem ё0 | Недопустимая Операция || | ёX rem ё0 | Недопустимая Операция || | +0 rem ёX | +0 || | -0 rem ёX | -0 || | +X rem ёY | +0 Y точно делит X || | -X rem ёY | -0 Y точно делит X || FSQRT | ё0 | *0 || Сравнение | ё0 : +X | ё0 < +X || | ё0 : ё0 | ё0 = ё0 || | ё0 : -X | ё0 > -X || FTST | ё0 | ё0 = 0 || FXAM | +0 | C3=1; C2=C1=C0=0 || | -0 | C3=C1=1; C2=C0=0 || FSCALE | ё0 масштабир. -oo | *0 || | ё0 масштабир. +oo | Недопустимая Операция || | ё0 масштабир. X | *0 || FXTRACT | +0 | ST=+0, ST(1)=-oo || | -0 | Деление на ноль || | | ST=-0, ST(1)=-oo || | | Деление на ноль || FPTAN | ё0 | *0 || FSIN (или резулт.| ё0 | *0 || SIN из FSINCOS) | | || FCOS (или резулт.| ё0 | +1 || COS из FSINCOS) | | || | | || FPATAN | ё0 / +X | *0 || | +0 / -X | *Пи || | ёX / ё0 | #Пи/2 || | ё0 / +0 | *0 || | ё0 / -0 | *Пи || | +oo / ё0 | +Пи/2 || | -oo / ё0 | -Пи/2 || | ё0 / +oo | *0 || | ё0 / -oo | *Пи || F2XM1 | +0 | +0 || | -0 | -0 || FYL2X | ёY x log(ё0) | Деление на ноль || | ё0 x log(ё0) | Недопустимая Операция || FYL2XP1 | +Y x log(ё0+1) | *0 || | -Y x log(ё0+1) | -*0 |+---------------------------------------------------------------+ X и Y ненулевые положительные операнды.1 когда отрицательное переполнение денормализует результат до нуля.2 знак, опрежделяемый режимом округления: + для округления до ближайшего,округления вверх или отсечения, - для округления вниз.3 при 0 < X < 1 и если не установлен режим округления вверх.4 при -1 < X < 0 и если не установлен режим округления вниз.* знак изначального нулевого операнда.# знак изначального операнда X.-# дополнение знака изначального операнда X.(+) исключающее ИЛИ знаков операндов