Есть ли сценарий, где можно использовать функцию FMA в libc?

Я наткнулся на эту страницу и обнаружил, что есть нечетная плавающая функция умножения - fma а также fmaf, Это говорит о том, что результат примерно такой:

 (x * y) + z             #fma(x,y,z)

И значение имеет бесконечную точность и округляется один раз до формата результата.

Однако, AFAICT, я никогда раньше не видел такой троичной операции. Так что мне интересно, что за использование Cumstom для этой функции.

2 ответа

Решение

Важным аспектом инструкции fused-multiply-add является (практически) бесконечная точность промежуточного результата. Это помогает с производительностью, но не так сильно, потому что две операции закодированы в одной инструкции. Это помогает с производительностью, потому что практически бесконечная точность промежуточного результата иногда важна, и очень дорого восстанавливать при обычном умножении и сложении, когда этот уровень Точность - это то, что нужно программисту.

Пример: сравнение a * b в 1.0

Предположим, что для алгоритма важно определить, где произведение двух чисел двойной точности a а также b по отношению к ненулевой константе (мы будем использовать 1.0). Число a а также b оба имеют полное значение двоичных цифр. Если вы вычисляете a*b как doubleрезультат может быть 1.0, но это не говорит вам, был ли фактический математический продукт немного ниже 1,0 и округлен до точно 1,0, или немного выше 1,0 и округлен вниз. Без FMA, ваши варианты:

  1. вычисление a*b как число с четверной точностью. Четверная точность не реализована в оборудовании, но есть библиотеки программной эмуляции. В четверной точности математический результат произведения является точно представимым, и вы можете сравнить его с 1,0.

  2. вычисление a*b с двойной точностью в режиме округления вверх и в режиме округления вниз. Если оба результата равны 1,0, это означает a*b точно 1,0. Если RU(a * b) больше 1,0, это означает, что математическое произведение выше 1,0, а если RD(a * b) ниже 1,0, это означает, что математическое произведение меньше 1,0. На большинстве процессоров этот подход означает изменение режима округления три раза, и каждое изменение является дорогостоящим (оно включает очистку конвейера ЦП).

С помощью инструкции FMA можно вычислить fma(a, b, -1.0) и сравните результат с 0,0. Так как числа с плавающей точкой плотнее около нуля, а промежуточный продукт не округляется в вычислениях, мы можем быть уверены, что fma(a, b, -1.0) > 0 означает математическое произведение a а также b больше 1 и так далее.

Пример: умножение Вельткампа / Деккера

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

Рассмотрим следующую функцию: Mul12(a, b), что занимает два числа с двойной точностью a а также b и вычисляет их произведение как двойное число Алгоритм, благодаря Вельткампу и Деккеру, вычисляет эту функцию только с добавлением и умножением с двойной точностью ( ссылка). Требуется 6 умножений (одно является частью каждого Split() плюс четыре в основной части алгоритма) и множество дополнений.

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

high = a * b; /* double-precision approximation of the real product */
low = fma(a, b, -high); /* remainder of the real product */
/* now the real product of a and b is available as the sum of high and low */

Больше примеров

Примерами, где FMA используется для его точности, а не только как инструкция, которая делает умножение и сложение, являются вычисления квадратного корня и деления. Эти операции должны быть правильно округлены (до ближайшего числа с плавающей запятой математического результата) в соответствии со стандартом IEEE 754. Эти две операции могут быть эффективно реализованы, когда доступна аппаратная инструкция FMA. Этот аспект обычно скрыт цепочкой компиляции, но в наборе команд IA-64 (Itanium) не было инструкции для деления. Вместо этого правильно округленное деление может быть получено с помощью последовательности инструкций (обычно генерируемых компилятором) с использованием FMA.

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

Другие вопросы по тегам