Можно-безопасно использовать стандартную программу?

Отвечая на вопрос, где я предложил -ffast-math, в комментарии указывалось, что это опасно.

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

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

Может ли ffast-math безопасно использоваться в обычном проекте?

Учитывая, что плавающая точка IEEE 754 имеет ошибки округления, предполагается, что вы уже живете с неточными вычислениями.


Этот ответ был особенно озадачен тем фактом, что -ffast-math выполняет гораздо больше, чем операции переупорядочения, что приведет к немного другому результату (не проверяет NaN или ноль, отключает нулевой знак, чтобы назвать несколько), но я не вижу, какие из них в конечном итоге будут в реальном коде.


Я попытался придумать типичное использование плавающих точек, и именно это я придумал:

  • GUI (2D, 3D, физический движок, анимация)
  • автоматизация (например, автомобильная электроника)
  • робототехника
  • промышленные измерения (например, напряжение)

и школьные проекты, но здесь это не имеет особого значения.

Ответ 1

Одна из особо опасных вещей, которую она делает, подразумевает -ffinite-math-only, что позволяет явным испытаниям NaN притворяться, что никаких NaN никогда не существует. Это плохая новость для любого кода, который явно обрабатывает NaN. Он попытается проверить NaN, но тест будет лежать сквозь зубы и утверждать, что ничто никогда не является NaN, даже если оно есть.

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

Более коварная проблема возникает, когда проверки NaN были там для проверки ошибок, для чего-то, что на самом деле не должно быть NaN. Но, возможно, через некоторую ошибку, плохие данные или другие эффекты -ffast-math, она становится NaN в любом случае. И теперь вы не проверяете его, потому что по предположению ничто никогда не является NaN, поэтому isnan является синонимом false. Все пойдет не так, ложно и долго после того, как вы уже отправили свое программное обеспечение, и вы получите "невозможный" отчет об ошибке - вы проверили для NaN, это прямо там, в коде, это не может быть неудачным! Но это потому, что кто-то когда-то добавил флагов -ffast-math, возможно, вы даже сделали это сами, не зная полностью, что он будет делать, или забыв, что вы использовали проверку NaN.

Итак, мы можем спросить, это нормально? Это становится весьма субъективным, но я бы не сказал, что проверка на NaN особенно ненормальна. Переход полностью круговым и утверждение, что это не нормально, потому что -ffast-math ломается, это, вероятно, плохая идея.

Он также много других страшных вещей, как описано в других ответах.

Ответ 2

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

Этот код говорил как эта невиновная конструкция:

float X, XMin, Y;
if (X < XMin)
{
    Y= 1 / (XMin - X);
    XMin= X;
}

Это иногда приводило к делению на нулевую ошибку, потому что когда сравнение проводилось, было использовано полное 80-битное представление (Intel FPU), а позже, когда вычитание выполнялось, значения были усечены до 32-битного представления, возможно, равным.

Ответ 3

Да, вы можете использовать -ffast-math для обычных проектов, для соответствующего определения "нормальных проектов". Это включает, вероятно, 95% всех написанных программ.

Но опять же, 95% всех написанных программ не принесли бы большой пользы от -ffast-math, потому что они не делают достаточно математики с плавающей запятой, чтобы это было важно.

Ответ 4

Учитывая, что плавающая точка IEEE 754 имеет ошибки округления, предполагается, что вы уже живете с неточными вычислениями.

Вопрос, на который вы должны ответить, заключается не в том, ожидает ли программа неточных вычислений (лучше было бы ожидать их, либо разломается с или без -ffast-math), но будет ли программа ожидать, что приближения будут точно такими, которые были предсказаны IEEE 754, и специальные значения, которые ведут себя точно так, как это было предсказано IEEE 754; или программа предназначена для работы с более слабой гипотезой о том, что каждая операция вводит небольшую непредсказуемую относительную ошибку.

Многие алгоритмы не используют специальные значения (бесконечности, NaN) и хорошо работают в вычислительной модели, в которой каждая операция вводит небольшую недетерминированную относительную ошибку. Эти алгоритмы хорошо работают с -ffast-math, потому что они не используют гипотезу о том, что ошибка каждой операции является точно ошибкой, предсказанной IEEE 754. Алгоритмы также работают нормально, когда режим округления отличается от по умолчанию от округлой до ближайшей: ошибка в конце может быть больше (или меньше), но FPU в режиме round-upwards также реализует вычислительную модель, которую ожидают эти алгоритмы, поэтому они работают более или менее одинаково хорошо в этих условиях.

Другие алгоритмы (например суммирование Kahan, "двойные" библиотеки, в которых числа представлены в виде суммы двух двухлокальных номеров), ожидая соблюдения правил в письме, поскольку они содержат интеллектуальные ярлыки, основанные на тонком поведении арифметики IEEE 754. Вы можете распознать эти алгоритмы из-за того, что они не работают, когда режим округления отличается от ожидаемого. Я как-то спросил вопрос о разработке двойных двойных операций, которые будут работать во всех режимах округления (для библиотечных функций, которые могут быть упреждаемы без возможности восстановления режима округления ): это дополнительная работа, и эти адаптированные реализации по-прежнему не работают с -ffast-math.

Ответ 5

Короткий ответ: Нет, вы не можете безопасно использовать -ffast-math, за исключением кода, предназначенного для использования с ним. Существуют всевозможные важные конструкции, для которых он порождает совершенно неправильные результаты. В частности, для сколь угодно больших x существуют выражения с правильным значением x, но которые будут оцениваться с помощью 0 с помощью -ffast-math или наоборот.

В качестве более расслабленного правила, если вы уверены, что код, который вы компилируете, был написан кем-то, кто на самом деле не понимает математику с плавающей запятой, используя -ffast-math, вероятно, неправильно делает результаты более неправильными (по сравнению с программист), чем они уже были. Такой программист не будет выполнять преднамеренное округление или другие операции, которые сильно сломаются, вероятно, не будут использовать насы и бесконечности и т.д. Наиболее вероятным отрицательным последствием являются вычисления, которые уже прервали проблемы и ухудшились. Я бы сказал, что такой код уже достаточно плох, что вы не должны использовать его в производстве для начала, с или без -ffast-math.

Из личного опыта у меня было достаточно ложных отчетов об ошибках от пользователей, пытающихся использовать -ffast-math (или даже тех, кто захотел его по умолчанию CFLAGS, uhg!), что я сильно склоняюсь к тому, чтобы поставить следующие фрагмент в любом коде с математикой с плавающей запятой:

#ifdef __FAST_MATH__
#error "-ffast-math is broken, don't use it"
#endif

Если вы все еще хотите использовать -ffast-math в процессе производства, вам необходимо потратить все усилия (много часов проверки кода), чтобы определить, безопасно ли это. Прежде чем это сделать, вы, вероятно, захотите сначала оценить, есть ли какая-либо выгода, которая стоит потратить на эти часы, и ответ, скорее всего, не будет.

Ответ 6

Да, они могут использоваться безопасно, при условии, что вы знаете, что делаете. Это означает, что вы понимаете, что они представляют величины, а не точные значения. Это означает:

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

На самом деле, я бы стал спорить. Если вы не работаете в очень специфических приложениях, где значения NaN и denormals имеют смысл, или если вам действительно нужен этот крошечный инкрементный бит воспроизводимости, тогда -ffast-math должен быть включен по умолчанию. Таким образом, ваши модульные тесты имеют больше шансов сбросить ошибки. В принципе, всякий раз, когда вы думаете, что вычисления fp имеют либо воспроизводимость, либо точность, даже при том, что вы ошибаетесь.