Арифметика с десятичной плавающей точкой ( DFP ) относится как к представлению, так и к операциям с десятичными числами с плавающей точкой . Работая напрямую с десятичными (основание 10) дробями, можно избежать ошибок округления, которые в противном случае обычно возникают при преобразовании между десятичными дробями (часто встречающимися в данных, вводимых человеком, таких как измерения или финансовая информация) и двоичными (основание 2) дробями.
Преимущество десятичного представления с плавающей точкой перед десятичным представлением с фиксированной точкой и целым числом заключается в том, что оно поддерживает гораздо более широкий диапазон значений. Например, в то время как представление с фиксированной точкой, которое выделяет 8 десятичных знаков и 2 десятичных знака, может представлять числа 123456,78, 8765,43, 123,00 и т. д., представление с плавающей точкой с 8 десятичными знаками может также представлять 1,2345678, 1234567,8, 0,000012345678, 12345678000000000 и т. д. Этот более широкий диапазон может значительно замедлить накопление ошибок округления во время последовательных вычислений; например, алгоритм суммирования Кахана может использоваться в числах с плавающей точкой для сложения большого количества чисел без асимптотического накопления ошибки округления.
Ранние механические применения десятичных чисел с плавающей точкой очевидны в счетах , логарифмических линейках , калькуляторах Смолвуда и некоторых других калькуляторах , которые поддерживают записи в научной нотации . В случае механических калькуляторов показатель степени часто рассматривается как побочная информация, которая учитывается отдельно.
Компьютер IBM 650 поддерживал 8-разрядный десятичный формат с плавающей точкой в 1953 году. [1] Двоичная машина Wang VS поддерживала 64-разрядный десятичный формат с плавающей точкой в 1977 году. [2] Motorola 68881 поддерживал формат с 17 цифрами мантиссы и 3 цифрами экспоненты в 1984 году, а библиотека поддержки плавающей точки для процессора Motorola 68040 обеспечивала совместимый 96-разрядный десятичный формат хранения с плавающей точкой в 1990 году. [2]
Некоторые компьютерные языки имеют реализации десятичной арифметики с плавающей точкой, включая PL/I , .NET , [3] emacs с calc и decimal-модуль Python . [ 4] В 1987 году IEEE выпустил IEEE 854 , стандарт для вычислений с десятичной плавающей точкой, в котором отсутствовала спецификация того, как данные с плавающей точкой должны кодироваться для обмена с другими системами. Впоследствии это было рассмотрено в IEEE 754-2008 , который стандартизировал кодирование десятичных данных с плавающей точкой, хотя и двумя различными альтернативными методами.
IBM POWER6 и более новые процессоры POWER включают DFP в аппаратное обеспечение, как и IBM System z9 [5] (и более поздние машины zSeries). SilMinds предлагает SilAx, настраиваемый векторный сопроцессор DFP . [6] IEEE 754-2008 определяет это более подробно. Fujitsu также имеет 64-битные процессоры Sparc с DFP в аппаратном обеспечении. [7] [2]
Стандарт IEEE 754-2008 определяет 32-, 64- и 128-битные десятичные представления с плавающей точкой. Как и в двоичных форматах с плавающей точкой, число делится на знак, экспоненту и значимую часть . В отличие от двоичных форматов с плавающей точкой, числа не обязательно нормализованы; значения с небольшим количеством значимых цифр имеют несколько возможных представлений: 1×10 2 =0,1×10 3 =0,01×10 4 и т. д. Когда значимая часть равна нулю, показатель степени может иметь любое значение.
Диапазоны экспонент были выбраны таким образом, чтобы диапазон, доступный для нормализованных значений, был приблизительно симметричным. Поскольку это невозможно сделать точно с четным числом возможных значений экспонент, дополнительное значение было присвоено Emax.
Определены два различных представления:
Оба варианта обеспечивают абсолютно одинаковый диапазон представимых значений.
Старшие два бита экспоненты ограничены диапазоном 0−2, а старшие 4 бита мантиссы ограничены диапазоном 0−9. 30 возможных комбинаций закодированы в 5-битном поле вместе со специальными формами для бесконечности и NaN .
Если старшие 4 бита мантиссы находятся в диапазоне от 0 до 7, то закодированное значение начинается следующим образом:
s 00mmm xxx Экспонента начинается с 00, значащая часть с 0mmms 01mmm xxx Экспонента начинается с 01, значащая часть с 0mmms 10mmm xxx Экспонента начинается с 10, значащая часть с 0mmm
Если первые 4 бита мантиссы представляют собой двоичные числа 1000 или 1001 (десятичные 8 или 9), то число начинается следующим образом:
s 1100m xxx Экспонента начинается с 00, значащая часть с 100ms 1101m xxx Экспонента начинается с 01, значащая часть с 100ms 1110m xxx Экспонента начинается с 10, значащая часть со 100m
Первый бит (s в приведенном выше примере) является знаковым битом, а последующие биты (xxx в приведенном выше примере) кодируют дополнительные биты экспоненты и остаток старшей значащей цифры, но детали различаются в зависимости от используемого варианта кодирования.
Окончательные комбинации используются для бесконечностей и NaN и одинаковы для обеих альтернативных кодировок:
s 11110 x ± Бесконечность (см. Расширенная прямая действительных чисел )s 11111 0 тихое NaN (знаковый бит игнорируется)s 11111 1 сигнализирует NaN (знаковый бит игнорируется)
В последнем случае все остальные биты кодировки игнорируются. Таким образом, можно инициализировать массив NaN, заполнив его однобайтовым значением.
Этот формат использует двоичную мантиссу от 0 до 10 p −1. Например, мантисса Decimal32 может быть до 10 7 −1 = 9 999 999 = 98967F 16 = 1001 1000100101 1001111111 2 . Хотя кодировка может представлять большие мантиссы, они недопустимы, и стандарт требует, чтобы реализации обрабатывали их как 0, если они встречаются на входе.
Как описано выше, кодировка различается в зависимости от того, находятся ли 4 старших бита мантиссы в диапазоне от 0 до 7 (от 0000 2 до 0111 2 ) или выше (1000 2 или 1001 2 ).
Если 2 бита после знакового бита равны «00», «01» или «10», то поле экспоненты состоит из 8 бит, следующих за знаковым битом (2 упомянутых бита плюс 6 бит «поля продолжения экспоненты»), а мантисса — это оставшиеся 23 бита с неявным ведущим битом 0, показанным здесь в скобках:
s 00eeeeee (0)ttt tttttttttt tttttttttt s 01eeeeee (0)ttt tttttttttt tttttttttt s 10eeeeee (0)ttt tttttttttt tttttttttt
Сюда входят субнормальные числа , у которых первая значащая цифра равна 0.
Если 2 бита после знакового бита равны "11", то 8-битное поле экспоненты сдвигается на 2 бита вправо (после знакового бита и битов "11" после него), а представленная мантисса находится в оставшихся 21 бите. В этом случае в истинной мантиссе имеется неявная (то есть не сохраненная) ведущая 3-битная последовательность "100":
s 1100eeeeee (100)t tttttttttt tttttttttt s 1101eeeeee (100)t tttttttttt tttttttttt s 1110eeeeee (100)t tttttttttt tttttttttt
Двухбитная последовательность «11» после знакового бита указывает на то, что к мантиссе неявно приставлен трехбитный префикс «100».
Обратите внимание, что ведущие биты поля значащей не кодируют самую старшую десятичную цифру; они просто являются частью большего чисто двоичного числа. Например, значащая часть 8 000 000 кодируется как двоичное число 0111 1010000100 1000000000 , где ведущие 4 бита кодируют 7; первая значащая часть, которая требует 24-го бита (и, следовательно, второй формы кодирования), равна 2 23 = 8 388 608 .
В приведенных выше случаях представленное значение равно:
Decimal64 и Decimal128 работают аналогично, но с большими полями продолжения экспоненты и мантиссы. Для Decimal128 вторая форма кодирования фактически никогда не используется; наибольшая допустимая мантисса 10 34 −1 = 1ED09BEAD87C0378D8E63FFFFFFFF 16 может быть представлена в 113 битах.
В этой версии мантисса хранится как ряд десятичных цифр. Ведущая цифра находится между 0 и 9 (3 или 4 двоичных бита), а остальная часть мантиссы использует плотно упакованную десятичную кодировку (DPD).
Ведущие 2 бита экспоненты и ведущая цифра (3 или 4 бита) мантиссы объединяются в пять бит, которые следуют за битом знака. За этим следует поле продолжения экспоненты с фиксированным смещением.
Наконец, поле продолжения мантиссы состоит из 2, 5 или 11 10-битных децитов , каждый из которых кодирует 3 десятичные цифры. [8]
Если первые два бита после знакового бита равны «00», «01» или «10», то это ведущие биты экспоненты, а три бита после них интерпретируются как ведущая десятичная цифра (от 0 до 7): [9]
Гребень. Показатель степени Знач. с 00 ТТТ (00)eeeeee (0TTT)[tttttttt][tttttttttt] с 01 ТТТ (01)eeeeee (0TTT)[tttttttt][tttttttttt] с 10 ТТТ (10)eeeeee (0TTT)[tttttttt][tttttttttt]
Если первые два бита после знакового бита равны «11», то вторые два бита являются ведущими битами экспоненты, а последний бит имеет префикс «100» для формирования ведущей десятичной цифры (8 или 9):
Гребень. Показатель степени Знач. с 1100 Т (00)eeeeee (100T)[tttttttttt][tttttttttt] с 1101 Т (01)eeeeee (100T)[tttttttttt][tttttttttt] с 1110 Т (10)eeeeee (100T)[tttttttttt][tttttttttt]
Оставшиеся две комбинации (11110 и 11111) 5-битного поля используются для представления ±бесконечности и NaN соответственно.
Обычное правило для выполнения арифметики с плавающей точкой заключается в том, что вычисляется точное математическое значение, [10] а затем результат округляется до ближайшего представимого значения с указанной точностью. Это на самом деле поведение, предписанное для IEEE-совместимого компьютерного оборудования, при нормальном поведении округления и при отсутствии исключительных условий.
Для простоты представления и понимания в примерах будет использоваться 7-значная точность. Основные принципы одинаковы при любой точности.
Простой метод сложения чисел с плавающей точкой — сначала представить их с тем же показателем степени. В примере ниже второе число сдвинуто вправо на 3 цифры. Продолжаем обычным методом сложения:
Следующий пример является десятичной системой, что означает, что основание равно 10.
123456,7 = 1,234567 × 10 5 101,7654 = 1,017654 × 10 2 = 0,001017654 × 10 5
Следовательно:
123456,7 + 101,7654 = (1,234567 × 10 5 ) + (1,017654 × 10 2 ) = (1,234567 × 10 5 ) + (0,001017654 × 10 5 ) = 10 5 × (1,234567 + 0,001017654) = 10 5 × 1,235584654
Это не что иное, как преобразование в научную запись . Подробно:
е=5; с=1,234567 (123456,7)+ е=2; с=1,017654 (101,7654)
е=5; с=1,234567+ e=5; s=0,001017654 (после сдвига)-------------------- e=5; s=1,235584654 (истинная сумма: 123558,4654)
Это истинный результат, точная сумма операндов. Он будет округлен до 7 цифр, а затем нормализован при необходимости. Окончательный результат:
е=5; s=1,235585 (конечная сумма: 123558,5)
Обратите внимание, что нижние 3 цифры второго операнда (654) по сути теряются. Это ошибка округления . В крайних случаях сумма двух ненулевых чисел может быть равна одному из них:
е=5; с=1,234567+ е=−3; с=9,876543
е=5; с=1,234567+ e=5; s=0,00000009876543 (после сдвига)---------------------- e=5; s=1,23456709876543 (истинная сумма) e=5; s=1,234567 (после округления/нормализации)
Другая проблема потери значимости возникает, когда вычитаются приближения к двум почти равным числам. В следующем примере e = 5; s = 1,234571 и e = 5; s = 1,234567 являются приближениями к рациональным числам 123457,1467 и 123456,659.
е=5; с=1,234571− е=5; с=1,234567---------------- е=5; с=0,000004 e=−1; s=4.000000 (после округления и нормализации)
Разница с плавающей точкой вычисляется точно, потому что числа близки — лемма Стербенца гарантирует это, даже в случае потери значимости, когда поддерживается постепенная потеря значимости . Несмотря на это, разница исходных чисел составляет e = −1; s = 4,877000, что отличается более чем на 20% от разницы e = −1; s = 4,000000 приближений. В крайних случаях все значимые цифры точности могут быть потеряны. [11] [12] Это сокращение иллюстрирует опасность предположения, что все цифры вычисленного результата имеют смысл. Борьба с последствиями этих ошибок является темой численного анализа ; см. также Проблемы точности.
При умножении мантиссы перемножаются, показатели степеней складываются, а результат округляется и нормализуется.
е=3; с=4,734612× е=5; s=5,417242----------------------- e=8; s=25,648538980104 (истинное произведение) е=8; s=25,64854 (после округления) e=9; s=2,564854 (после нормализации)
Деление выполняется аналогично, но это сложнее.
Нет проблем отмены или поглощения при умножении или делении, хотя небольшие ошибки могут накапливаться, поскольку операции выполняются повторно. На практике способ выполнения этих операций в цифровой логике может быть довольно сложным.
{{cite book}}
: CS1 maint: location missing publisher (link)