Войти
ПрограммированиеСтатьиОбщее

Детали плавающей точки (3 стр)

Автор:

Семантика операций

Стандарт определяет семантику 83 операций над двоичными числами с плавающей точкой (для десятичных чисел с плавающей точкой набор операций слегка другой).
Данная статья не ставит своей целью полное изложение стандарта, поэтому интересующиеся полным определением всех операций отсылаются к тексту стандарта.
Список операций полностью приводится ниже:

+ Показать

Некоторые операции могут в определённых ситуациях генерировать исключения. Об исключениях - см. раздел Исключения.

Стоит отметить, что стандарт определяет семантику только этих операций. Семантику других операций (например стандартных математических функции: синус, логарифм и т. д.) имеет смысл искать в документации к библиотеке, предоставляющей эти функции. Однако, конкретно для стандартных математических функций стандарт предоставляет рекомендации.

Список этих функций приводится ниже:

+ Показать

Все эти функции рекомендуется реализовывать правильно округленными (определение правильного округления см. ниже).
Описание конкретных (рекомендуемых) требований к этим функциям см. в разделе 9.2 стандарта.

Измерение точности в ULP

Для характеризации точности полезно ввести понятие единица младшего разряда мантиссы (англ. unit in the last place, ULP). В тексте стандарта эта величина носит название квант (англ. quantum).

Смысл понятия очевиден из названия. Квант также равен расстоянию между соседними представимыми числами с данной экспонентой.

Для нормализованного числа с p разрядами мантиссы (и t=p−1 хвостовыми разрядами мантиссы) и смещённой экспонентой E (и несмещённой экспонентой e=Ebias):
\(1\, \mathrm{ULP} = 2^{E-bias-p+1}=2^{e-t}\)

Для субнормального:
\(1\, \mathrm{ULP} = 2^{2-bias-p}\), та же, что и для следующей экспоненты (E=1).

Также эта величина для нормализованного числа может быть вычислена как:
\(1\, \mathrm{ULP}(x) = 2^{\lfloor log_2(\left| x \right|) \rfloor - t}\)
Здесь t - количество хвостовых бит мантиссы.

Направление округления

Понятие направление округления является ключевым для понимания операций IEEE 754.

Т. к. вещественных чисел - бесконечное множество, то не все они могут быть представлены в заданном формате.

Любое вещественное число либо представимо точно, либо лежит между двумя представимыми числами с плавающей точкой (это обеспечивается наличием в IEEE 754 значений \(\pm \infty\)).
0 - единственное вещественное число, точно представимое не единственным образом (\(\pm 0\)).

Направление округления задаёт правило, по которому из двух соседних представимых чисел выбирается то, которым будет представлено данное вещественное число.

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

На практике, конечно же, набор операций выбран так, что существуют алгоритмы, дающие тот же результат за конечное время, но стандарт, будучи спецификацией, не утруждает себя доказательством (и вообще упоминанием) этого факта.

Стандарт определяет 5 направлений округления:

roundTiesToEven (используется по умолчанию) - округление ведётся к ближайшему (в смысле расстояния, т. е. абсолютной величины разности) представимому числу ("середина" между бесконечностью и максимальным/минимальным конечным числом находится на 0.5 ULP за пределами этого числа); если вещественное число лежит ровно посередине между двумя представимыми, то выбирается "более чётное" из них, т. е. то, у которого младший бит мантиссы равен 0 (см. Наблюдение 4 в разделе Представление чисел с плавающей точкой).

roundTiesToAway (для двоичных форматов является необязательным) - округление ведётся к ближайшему (в смысле расстояния, т. е. абсолютной величины разности) представимому числу ("середина" между бесконечностью и максимальным/минимальным конечным числом находится на 0.5 ULP за пределами этого числа); если вещественное число лежит ровно посередине между двумя представимыми, то выбирается большее по абсолютной величине.

roundTowardPositive - округление ведётся к ближайшему представимому числу, не меньшему, нежели данное.

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

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

Из этих режимов roundTiesToEven и roundTiesToAway - более точные: для них ошибка округления не превышает 0.5 ulp. В остальных 3-х режимах ошибка округления не превышает 1 ulp.

Следует понимать, что у выбора режима округления есть и другие следствия. В частности, в режиме roundTowardZero результаты операций сложения, вычитания и умножения конечных представимых чисел не могут быть округлены к \(\pm \infty\). Это свойство может иметь самостоятельную ценность.

NaN округлению не подлежат.

Как видно из таблицы выше, некоторые операции указывают направление округления явно, но большинство использует текущее направление округления, являющееся частью состояния системы.

Стандарт требует от реализации предоставить возможность выбирать направление округления хотя бы на этапе компиляции, и рекомендует давать возможность выбирать направление округления во время исполнения.

Приведение между типами с плавающей точкой

Для всех поддерживаемых типов с плавающей точкой определена операция приведения ко всем другим поддерживаемым типам с плавающей точкой, округляющая (к целевому типу) в текущем направлении округления.

Стандартные арифметические операции

Стандарт определяет 6 стандартных арифметических операций:

  • сложения, вычитание, умножение, деление
  • квадратный корень
  • объединённое умножение и сложение (fused multiply-add)
  • Fused multiply-add (FMA) определяется как
    \(FMA(x, \, y, \, z)=(x \times y) + z\)
    и отличается от последовательных умножения и сложения тем, что рассматривается как единая операция, с однократным округлением в конце.

    Квадратный корень определён для всех неотрицательных чисел. Для отрицательных чисел и NaN результатом является NaN. Результат вычисления квадратного корня имеет положительный знак для всех аргументов \(\geq 0\) за единственным исключением: \(\mathrm{sqrt}\, (-0) = -0\). Такое определение, с т. з. Уильяма Кэхэна, приводит к более логичному поведению разрезов в комплексной плоскости.

    Все эти операции поддерживают смешанную арифметику между разными форматами с плавающей точкой. Конкретнее, форматы аргументов могут отличаться между собой, и отличаться от формата результата.

    Все операции дают правильно округленный результат в текущем направлении округления.

    Приведение к целому типу и от целого типа

    Стандарт определяет преобразования

  • целое число → число с плавающей точкой
  • число с плавающей точкой → целое число
  • Операции определены как для знаковых, так и для беззнаковых целочисленных типов.

    Операция "целое число → число с плавающей точкой" возвращает правильно округленный результат (в текущем режиме округления). В частности - она точная для всех целых чисел, точно представимых в двнном типе с плавающей точкой.

    Для целочисленных типов, способных представлять знаковый 0 (напр. 1-complement) - знак 0 сохраняется. Для остальных (т. е., на практике - почти всегда, в силу повсеместности 2-complement) - знак 0 принимается положительным.

    Операции "число с плавающей точкой → целое число" принимают направление округления явно и, согласно стандарту, представлены в 2-х видах - обычние и генерирующие inexactException при округлении (стандарт требует, чтобы встроенные неявные преобразования в языке программирования были реализованы операциями 2-го вида).

    Преобразование бесконечности, NaN или значения за пределами представимого диапазона целочисленного типа генерирует invalidOperationException, если нет другого способа обозначить этот факт (напр. архитектура IA64 предоставляла целочисленный NaN). Возвращаемое в этом случае значение стандарт не определяет.

    Приведение к целочисленному значению

    Результатом является (ближайшее) число с плавающей точкой того же типа, что и аргумент, являющееся целым числом.

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

    Бесконечность преобразуется в бесконечность.

    Знаки нулей и бесконечностей сохраняются.

    Эти операции соответствуют в т. ч. математическим функциям  \(\mathrm{floor}\) (roundToIntegralTowardNegative) и \(\mathrm{ceil}\) (roundToIntegralTowardPositive).

    Стандарт определяет версию, генерирующую inexactException при округлении.

    Приведение к текстовому виду и из него

    Стандарт различает 2 вида текстовых представлений - десятичные и шестнадцатеричные (соответствующие шестнадцатеричным константам с плавающей точкой C99).

    Количество разрядов текстового представления является параметром функции (операции).

    Свойства преобразований:
    0. Используется текущее направление округления.
    1. В режиме округления по умолчанию (roundTiesToEven) приведение к текстовому виду и обратно (при достаточном количестве разрядов) не изменяет значение. Минимальное достаточное для этого количество десятичных разрядов определяется таблицей:

    binary165
    binary329
    binary6417
    binary12836
    binary{k}\(1+\lceil p \times log_{10}(2) \rceil\)

    2. Преобразования к шестнадцатеричным константам - точные. Приведение туда и обратно - не изменяет значение.
    3. Исключение к 2-м предыдущим пунктам: допустимо преобразование sNaN в qNaN.
    4. В случае преобразования на этапе компиляции (в частности - интерпретация литералов) подразумевается направление округления по умолчанию (roundTiesToEven), в отсутствие директив, указывающих альтернативное направление.
    5. \(\infty\) преобразуется в "inf" или "infinity" с точностью до регистра (т. е. "Inf" и "INFINITY" - тоже допустимы). Знак сохраняется. Вывод положительного знака не обязателен.
    6. qNaN преобразуется в "nan" с точностью до регистра. sNaN преобразуется (с точностью до регистра) либо в "snan" либо в "nan" (в этом случае генерируется invalidOperationException). Вывод знака не обязателен. "nan" (с точностью до регистра) считывается как qNaN, "snan" (с точностью до регистра) считывается либо как sNaN, либо как qNaN (в этом случае генерируется invalidOperationException). Знак не обязателен. Допустим (но не обязателен) определяемый реализацией способ представления payload для NaN.
    7. Все преобразования конечных чисел из/к текстового представления не более чем H разрядов длиной - правильно округлены. Стандарт требует H не меньше, чем 3 плюс длина достаточная для выполнения п.1 для наиболее длинного из поддерживаемых типов. Стандарт рекомендует H=∞.
    8. Преобразования к текстовому представлению из более, чем H разрядов - заполняют оставшиеся разряды нулями.
    9. Преобразования из текстового представления из более, чем H разрядов (или превышающее представимый диапазон экспонент) - сначала округляется в выбранном (десятичном!, направления для двоичного и десятичного округления задаются отдельно) режиме до H разрядов, после чего округляется в соответствии с п. 7. Первый этап может генерировать исключения.
    10. Преобразования - монотонные функции.
    11. Конкретный формат записи текстового представления конечных чисел - определяется реализацией.
    12. Кодировка (ASCII, Unicode) стандартом не оговаривается.

    Исключения

    В некоторых ситуациях операции с плавающей точкой генерируют исключения. Исключения не являются ошибками: цитируя Уильяма Кэхена

    They are called  “Exceptions”  because to any policy for handling them,  imposed in advance upon all programmers by the computer system,  some programmers will have good reasons to take exception.

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

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

    Стандарт определяет 5 исключений:

    ИсключениеОписаниеВозвращаемое значение
    Invalid operationаргументы некорректны для данной операцииqNaN
    Division by zeroделение на 0бесконечность соответствующего знака
    Overflowрезультат (до округления) превышает (по абсолютному значению) максимальное представимое конечное числоокругленный результат
    Underflowрезультат меньше (по абсолютному значению) минимального нормализованного представимого числаокругленный результат
    Inexactрезультат не представим точноокругленный результат

    Примечание 1: для Underflow "результат" может пониматься до или после округления - на усмотрение реализации, но одинаково для всех операций
    Примечание 2: для Overflow в зависимости от направления округления возвращаемое значение может быть не бесконечностью

    Пользователь может читать и устанавливать флаги.

    Другие операции также могут вызывать исключения: например, логарифм (который стандарт не определяет а только предоставляет рекомендации) может вызывать Invalid operation для отрицательных аргументов и Division by zero для 0 (именно это поведение рекомендовано стандартом).

    Стандарт также рекомендует реализации предоставлять программисту возможность установить собственные обработчики данных исключений. Стандарт различает 2 вида обработчиков: собственно обработчики (exception handler block) - после их вызова выполнение продолжается с места возникновения исключения; и переходы (transfer) - к месту возникновения исключения не возвращаются. И те и другие могут быть немедленными (immediate) и отложенными (delayed).

    Список рекомендованных exception handler blocks:

  • default (raise flag)
  • raiseNoFlag
  • mayRaiseFlag
  • recordException
  • substitute(x)
  • substituteXor(x)
  • abruptUnderflow
  • За деталями читатель отсылается к тексту стандарта.

    Конкретные transfer специфичны языку и стандартом не определяются. В качестве примеров приводятся break, throw exceptionName, goto label.

    О востребованности исключений см. в Handling Floating-Point Exceptions in Numeric Programs.

    Страницы: 1 2 3 4 5 6 7 Следующая »

    #floating point, #математика

    4 мая 2017 (Обновление: 31 дек 2018)

    Комментарии [23]