Почему плавающий расчет и приведение к разным результатам в конфигурации отладки и выпуска показывают разные результаты? - PullRequest
9 голосов
/ 10 февраля 2012

Это действительно странная ошибка для меня, и мне потребовалось много времени, чтобы понять, что происходит. Чтобы упростить вещи и воспроизвести, просто создайте пустое консольное приложение win32 с использованием VS2005 и используйте этот код в основном методе:

float a = 411.00418f;
float b = 1.0f;
float c = 0.076279849f;
unsigned short result = (unsigned short)( (a-b)/c );
unsigned short result2 = (unsigned short)( (float)((a-b)/c) );
// Debug: 5374, 5375
// Release: 5374, 5374
printf("%d, %d\n", result, result2);  

Почему result2 показывает другое значение в режиме отладки / выпуска?

1 Ответ

10 голосов
/ 10 февраля 2012

В MSVC режим с плавающей точкой по умолчанию - precise (/fp:precise). Это означает, что оптимизатор может выполнять определенные оптимизации для повышения точности или производительности.

Попробуйте изменить режим на strict (/fp:strict). Это заставит компилятор следовать строгим правилам с плавающей точкой при округлении и тому подобное.

(РЕДАКТИРОВАТЬ: strict (/fp:strict), похоже, не работает в этом случае ...)

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

push    5374                    ; 000014feH
push    5374                    ; 000014feH
push    OFFSET ??_C@_07MHMABKGB@?$CFd?0?5?$CFd?6?$AA@
call    DWORD PTR __imp__printf
add esp, 12                 ; 0000000cH

РЕДАКТИРОВАТЬ: Это похоже на ошибку оптимизатора компилятора.

При strict (/fp:strict) следующий код дает разные результаты:

float a = 411.00418f;
float b = 1.0f;
float c = 0.076279849f;

unsigned short result1 = (unsigned short)((float)((a-b)/c));

float d = (float)((a-b)/c);
unsigned short result2 = (unsigned short)( d );

Выход:

5374, 5375

Извлечение (float)((a-b)/c) в отдельное назначение не должно влиять на результаты в strict (/fp:strict).


Я знаю одного из ребят, которые работают над оптимизатором MSVC. Я пришлю ему сообщение об ошибке.

Обновление:

Вот их ответ:

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

FWIW, ошибка не воспроизводится, если вы выбрасываете / arch: SSE2, и поскольку мы по умолчанию включают / arch: SSE2 для следующего выпуска VC ++ (https://connect.microsoft.com/VisualStudio/feedback/details/688736/compiler-generates-sse-instructions-without-arch-sse).

Итак, поведение по умолчанию покажет, что эта ошибка исправлена. Но если Вы вернетесь к старой модели FP (throw / arch: IA32), ошибка может все еще присутствовать.

Эрик

Итак, они подтвердили это как ошибку.

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