странные результаты с / fp: fast - PullRequest
4 голосов
/ 15 июня 2010

У нас есть код, который выглядит следующим образом:

inline int calc_something(double x) {
  if (x > 0.0) {
    // do something
    return 1;
  } else {
    // do something else
    return 0;
  }
}

К сожалению, при использовании флага /fp:fast мы получаем calc_something(0)==1, поэтому мы явно выбираем неправильный путь кода.Это происходит только тогда, когда мы используем метод в нескольких точках нашего кода с разными параметрами, поэтому я думаю, что здесь происходит некоторая подозрительная оптимизация от компилятора (Microsoft Visual Studio 2008, SP1).

Кроме того,вышеуказанная проблема исчезает, когда мы меняем интерфейс на

inline int calc_something(const double& x) {

Но я понятия не имею, почему это исправляет странное поведение.Кто-нибудь может объяснить это поведение?Если я не могу понять, что происходит, нам придется убрать переключатель /fp:fast, но это сделает наше приложение немного медленнее.

Ответы [ 5 ]

6 голосов
/ 15 июня 2010

Я недостаточно знаком с FPU, чтобы комментировать с уверенностью, но я предполагаю, что компилятор позволяет существующему значению, которое, по его мнению, должно равняться x, сидеть в этом сравнении. Возможно, вы идете y = x + 20.; y = y - 20; y уже в стеке FP, поэтому вместо загрузки x компилятор просто сравнивает с y. Но из-за ошибок округления, y не совсем 0.0, как это должно быть, и вы получите странные результаты, которые вы видите.

Для лучшего объяснения: Почему cos (x)! = Cos (y), хотя x == y? из C ++ FAQ lite. Это часть того, что я пытаюсь донести до меня, я просто не мог вспомнить, где именно я это прочитал до сих пор.

Изменение константной ссылки исправляет это, потому что компилятор беспокоится о псевдонимах. Он вызывает загрузку с x, потому что не может предположить, что его значение не изменилось в какой-то момент после создания y, и поскольку x на самом деле точно 0.0 [, который представлен в каждом формате с плавающей запятой, который я я знаком с] ошибки округления исчезают.

Я почти уверен, что MS предоставляет прагму, которая позволяет вам устанавливать флаги FP для каждой функции. Или вы можете переместить эту процедуру в отдельный файл и присвоить этому файлу настраиваемые флаги. В любом случае, это может предотвратить страдания всей вашей программы, просто чтобы эта рутина была счастлива.

3 голосов
/ 15 июня 2010

Как я уже говорил в другом вопросе, компиляторы отстой при генерации кода с плавающей запятой. Ссылка на статью Денниса хорошо объясняет проблемы. Вот еще: Статья MSDN .

Если производительность кода важна, вы можете легко 1 превзойти компилятор, написав свой собственный код ассемблера. Если ваш алгоритм векторизован, то вы также можете использовать SIMD (с небольшой потерей точности).

  1. Предполагая, что вы понимаете, как работает FPU.
2 голосов
/ 15 июня 2010

inline int calc_something(double x) (вероятно) будет использовать 80-битный регистр.inline int calc_something(const double& x) будет хранить двойник в памяти, где он занимает 64 бита.Это, по крайней мере, объясняет разницу между ними.

Тем не менее, я считаю ваш тест довольно сомнительным для начала.Результаты calc_something чрезвычайно чувствительны к округлению его входных данных.Ваши алгоритмы FP должны быть устойчивы к округлению.calc_something(1.0-(1.0/3.0)*3) должно совпадать с calc_something(0.0).

2 голосов
/ 15 июня 2010

каковы результаты calc_something(0L) или calc_something(0.0f)?Это может быть связано с размером типов перед приведением.Целое число - 4 байта, двойное - 8.

Вы пытались посмотреть на ассемблированный код, чтобы увидеть, как выполняется вышеупомянутое преобразование?

Я нашел Google 'fp fast', я нашел этот пост [social.msdn.microsoft.com]

1 голос
/ 15 июня 2010

Я думаю, что поведение правильное.

Вы никогда не сравниваете число с плавающей точкой с точностью, меньшей точности типа удержания.

То, что исходит из нуля, может быть равным, большим или меньшимчем другой ноль.

См. http://floating -point-gui.de /

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...