Что на самом деле делает математика gcc?
Я понимаю, что GCC --ffast-math
Флаг может значительно увеличить скорость операций с плавающей запятой и выходит за рамки стандартов IEEE, но я не могу найти информацию о том, что на самом деле происходит, когда он включен. Может ли кто-нибудь объяснить некоторые детали и, возможно, дать четкий пример того, как что-то изменилось бы, если флаг был включен или выключен?
Я попытался покопаться в SO, чтобы найти похожие вопросы, но не смог найти ничего, объясняющего работу ffast-math.
2 ответа
Как вы упомянули, он допускает оптимизации, которые не сохраняют строгое соответствие IEEE.
Пример таков:
x = x*x*x*x*x*x*x*x;
в
x *= x;
x *= x;
x *= x;
Поскольку арифметика с плавающей точкой не ассоциативна, порядок и факторизация операций будут влиять на результаты из-за округления. Следовательно, эта оптимизация не выполняется при строгом поведении FP.
На самом деле я не проверял, выполняет ли GCC именно эту оптимизацию. Но идея та же самая.
-ffast-math
делает гораздо больше, чем просто нарушает строгое соответствие IEEE.
Прежде всего, конечно, это нарушает строгое соответствие IEEE, позволяя, например, переупорядочивать инструкции к чему-то, что математически одинаково (в идеале), но не совсем одинаково с плавающей запятой.
Во-вторых, это отключает настройку errno
после математических функций с одной инструкцией, что означает избегание записи в локальную переменную потока (это может иметь 100% -ное различие для этих функций на некоторых архитектурах).
В-третьих, он предполагает, что вся математика является конечной, что означает, что никакие проверки на NaN (или ноль) не производятся там, где они будут иметь вредные последствия. Просто предполагается, что этого не произойдет.
В-четвертых, он обеспечивает взаимное приближение для деления и обратного квадратного корня.
Кроме того, он отключает знаковый ноль (код предполагает, что нулевой знак не существует, даже если цель его поддерживает) и математика округления, что позволяет, среди прочего, выполнять постоянное свертывание во время компиляции.
Наконец, он генерирует код, который предполагает, что никакие аппаратные прерывания не могут произойти из-за математики сигнализации / перехвата (то есть, если они не могут быть отключены на целевой архитектуре и, следовательно , произойдут, они не будут обрабатываться).