Я понимаю, что --ffast-math
флаг gcc может значительно увеличить скорость операций с плавающей запятой и выходит за рамки стандартов IEEE, но я не могу найти информацию о том, что на самом деле происходит, когда он включен. Может ли кто-нибудь объяснить некоторые детали и, возможно, дать четкий пример того, как что-то изменилось бы, если флаг был включен или выключен?
Я попытался покопаться в SO для похожих вопросов, но не смог найти ничего, объясняющего работу ffast-math.
double
, но варьируется в зависимости от приложения). Стоит отметить, что оптимизация ffast-math не обязательно добавляет округление «больше». Единственная причина, почему он не соответствует IEEE, заключается в том, что ответ отличается (хотя и немного) от того, что написано.x
меньше 10, ошибка в примере с Mystical будет ниже 10 ^ -10. Но еслиx = 10e20
ошибка, вероятно, будет много миллионов.-fassociative-math
который включен в-funsafe-math-optimizations
котором , в свою очередь включена-ffast-math
Почему не GCC оптимизируютa*a*a*a*a*a
к(a*a*a)*(a*a*a)
?-ffast-math
делает намного больше, чем просто нарушает строгое соответствие IEEE.Прежде всего, конечно, это нарушает строгое соответствие IEEE, позволяя, например, переупорядочивать инструкции к чему-то, что математически совпадает (в идеале), но не точно то же самое с плавающей запятой.
Во-вторых, он отключает настройку
errno
после математических функций с одной инструкцией, что означает избегание записи в локальную переменную потока (это может иметь 100% -ное различие для этих функций на некоторых архитектурах).В-третьих, он предполагает, что вся математика является конечной , что означает, что никакие проверки на NaN (или ноль) не производятся там, где они будут иметь вредные эффекты. Просто предполагается, что этого не произойдет.
В-четвертых, это позволяет использовать взаимные аппроксимации для деления и обратного квадратного корня.
Кроме того, он отключает знаковый ноль (код предполагает, что нулевой знак не существует, даже если цель его поддерживает) и математика округления, что позволяет, среди прочего, выполнять постоянное свертывание во время компиляции.
Наконец, он генерирует код, который предполагает, что никакие аппаратные прерывания не могут произойти из-за математики сигнализации / перехвата (то есть, если они не могут быть отключены на целевой архитектуре и, следовательно , произойдут , они не будут обрабатываться).
источник
-ffast-math
Устанавливает -fno-math-errno, -funsafe-math-optimizations, -ffinite-math-only, -fno-rounding-math, -fno-signaling -nans и -fcx-limited-range. Этот параметр вызывает определение макроса препроцессора FAST_MATH . "и что-то из glibc, например (math.h
рядом с math_errhandling)". По умолчанию все функции поддерживают обработку как errno, так и обработки исключений. В быстром математическом режиме gcc и если определены встроенные функции, это может быть не так. "-ffast-math
позволяет компилятору срезать некоторые углы и нарушать некоторые обещания (как объяснено), что в целом не опасно как таковое и не является проблемой для большинства людей. Для большинства людей это то же самое, только быстрее. Однако, если ваш код предполагает и полагается на эти обещания, тогда ваш код может вести себя не так, как вы ожидаете. Как правило, это означает , что программа будет , кажется , работает хорошо, в основном, но некоторые результаты могут быть «неожиданными» (скажем, в симуляции физики, два объекта может не Collide должным образом).-O2
как правило, включает «каждую» легальную оптимизацию, за исключением тех, которые обменивают размер на скорость.-O3
также позволяет оптимизировать этот размер для скорости. Это все еще поддерживает 100% -ую корректность.-ffast-math
пытается ускорить математические операции, допуская «слегка некорректное» поведение, которое обычно не вредно, но будет считаться неверным в формулировке стандарта. Если ваш код действительно сильно отличается по скорости на двух компиляторах (не только на 1-2%), то убедитесь, что ваш код строго соответствует стандартам и ...#pragma omp parallel for
, и в теле цикла вы читаете и пишете по адресам, указанным аргументами функции, и выполняете нетривиальное количество ветвлений. Как необразованное предположение, вы могли бы перебивать кеши из-за определенного вами потока реализации, и MSVC может некорректно избегать промежуточных хранилищ, которые предписывают правила наложения имен. Невозможно сказать.