Всегда ли команды FMA (слитые с умножением-сложением) дают тот же результат, что и команда затем добавить?
У меня есть эта сборка (AT&T синтаксис):
mulsd %xmm0, %xmm1
addsd %xmm1, %xmm2
Я хочу заменить его на:
vfmadd231sd %xmm0, %xmm1, %xmm2
Будет ли это преобразование всегда оставлять эквивалентное состояние во всех задействованных регистрах и флагах? Или результат будет немного отличаться? (Если они отличаются, то почему?)
(Об инструкциях FMA: http://en.wikipedia.org/wiki/FMA_instruction_set)
1 ответ
Нет. Фактически, большая часть преимущества объединенного умножения-сложения состоит в том, что он (не обязательно) дает тот же результат, что и отдельное умножение и сложение.
В качестве (несколько надуманного) примера предположим, что мы имеем:
double a = 1 + 0x1.0p-52 // 1 + 2**-52
double b = 1 - 0x1.0p-52 // 1 - 2**-52
и мы хотим вычислить a*b - 1
, "Математически точное" значение a*b - 1
является:
(1 + 2**-52)(1 - 2**-52) - 1 = 1 + 2**-52 - 2**52 - 2**-104 - 1 = -2**-104
но если мы сначала вычислим a*b
используя умножение, он округляет до 1,0, поэтому последующее вычитание 1,0 дает нулевой результат.
Если мы используем fma(a,b,-1)
вместо этого мы исключаем промежуточное округление продукта, что позволяет нам получить "реальный" ответ, -1.0p-104
,
Обратите внимание, что мы не только получаем другой результат, но также были установлены и другие флаги; Отдельное умножение и вычитание устанавливает неточный флаг, тогда как слияние-умножение-сложение не устанавливает никаких флагов.