Значения с плавающей точкой ведут себя по-разному в сборках release и debug

StackOverflow https://stackoverflow.com/questions/141752

Вопрос

Мое приложение генерирует разные значения с плавающей запятой, когда я компилирую его в режиме выпуска и в режиме отладки.Единственная причина, по которой я узнал, заключается в том, что я сохраняю двоичный журнал трассировки, а журнал из сборки release немного отличается от сборки debug, похоже, что два нижних бита 32-битных значений с плавающей запятой отличаются примерно в 1/2 случаев.

Считаете ли вы это "различие" ошибкой или можно ожидать такого типа различий?Будет ли это ошибкой компилятора или внутренней ошибкой библиотеки?

Например:

LEFTPOS and SPACING are defined floating point values.
float def_x;
int xpos;

def_x = LEFTPOS + (xpos * (SPACING / 2));

Проблема связана с компилятором X360.

Это было полезно?

Решение

В режиме выпуска может быть установлена другая стратегия FP.Существуют различные режимы арифметики с плавающей запятой в зависимости от желаемого уровня оптимизации.MSVC, например, имеет строгий, быстрый и точный режимы.

Другие советы

Я знаю, что на ПК регистры с плавающей запятой имеют ширину 80 бит.Таким образом, если вычисление выполняется полностью в FPU, вы получаете преимущество в 80 битах точности.С другой стороны, если промежуточный результат переносится в обычный регистр и обратно, он усекается до 32 бит, что дает другие результаты.

Теперь рассмотрим, что релизная сборка будет иметь оптимизации, которые сохраняют промежуточные результаты в регистрах FPU, тогда как отладочная сборка, вероятно, будет наивно копировать промежуточные результаты взад и вперед между памятью и регистрами - и вот вам разница в поведении.

Я не знаю, происходит ли это и на X360 или нет.

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

Взгляните на /fp (Указывает поведение с плавающей запятой).

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

В дополнение к различным режимам работы с плавающей запятой, на которые указывали другие, для выпуска могут быть включены SSE или аналогичные векторные оптимизации.Преобразование арифметики с плавающей запятой из стандартных регистров в векторные регистры может повлиять на младшие биты ваших результатов, поскольку векторные регистры обычно будут более узкими (меньше битов), чем стандартные регистры с плавающей запятой.

Это не жук.Такого рода различий следовало ожидать.

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

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

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

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

Если вам нужны согласованные результаты, вы можете сделать переменные изменчивыми, что приведет к более медленным, менее точным, но согласованным результатам.

Если вы установили переключатель компилятора, который позволял компилятору изменять порядок операций с плавающей запятой, - например/ fp: быстро - тогда, очевидно, это не ошибка.

Если вы не установили ни одного такого параметра, то это ошибка - стандарты C и C ++ не позволяют компиляторам изменять порядок операций без вашего разрешения.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top