2012-02-10 14 views
9

To naprawdę dziwny błąd i zajęło mi dużo czasu, aby dowiedzieć się, co się dzieje. Aby uprościć i rozmnażać, wystarczy utworzyć pustą aplikację konsoli win32 przy użyciu VS2005 i użyć tego kodu w głównym sposobem:Dlaczego obliczenia zmiennoprzecinkowe i rzutowanie pokazują inny wynik w konfiguracji debugowania i wydania?

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); 

Dlaczego wynik2 pokazuje inną wartość w trybie debug/release?

Odpowiedz

10

W MSVC domyślny tryb zmiennoprzecinkowy to precise (/fp:precise). Oznacza to, że optymalizator może dokonać pewnych optymalizacji, aby poprawić dokładność lub wydajność.

Spróbuj zmienić tryb na strict (/fp:strict). Spowoduje to, że kompilator będzie przestrzegać ścisłych reguł zmiennoprzecinkowych dotyczących zaokrąglania i takich.

(EDIT: strict (/fp:strict) nie wydają się działać w tym przypadku ...)

Jeśli spojrzeć na demontażu zoptymalizowanej konstrukcji, można zobaczyć, że cała obliczeń została złożona i zoptymalizowany na zewnątrz.

push 5374     ; 000014feH 
push 5374     ; 000014feH 
push OFFSET [email protected][email protected][email protected] 
call DWORD PTR __imp__printf 
add esp, 12     ; 0000000cH 

EDIT: To wygląda jak błąd kompilatora optymalizator mnie.

Pod strict (/fp:strict) dodaje kod generuje różne wyniki:

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); 

wyjściowy:

5374, 5375 

wyciągając (float)((a-b)/c) do osobnego przypisania nie powinny wpływać na wyniki pod strict (/fp:strict).


Znam jeden z tych facetów, którzy pracują na optymalizator MSVC. Wyślę mu raport o błędzie.

Aktualizacja:

Oto ich odpowiedź:

Cześć Alex, dzięki za tym raporcie. Spróbuję to naprawić dla nadchodzącego wydania VC++ o numerze , ale może się nie uda.

FWIW, błąd nie reprodukować jeśli rzucisz/arch: SSE2, a ponieważ umożliwiają: SSE2/arch domyślnie do następnego VC++ zwolnić (https://connect.microsoft.com/VisualStudio/feedback/details/688736/compiler-generates-sse-instructions-without-arch-sse).

Domyślne zachowanie pokazuje, że ten błąd został naprawiony. Ale jeśli powrócisz do starego modelu FP (throw/arch: IA32), błąd może nadal być obecny.

Eric

Więc oni potwierdził to jako błąd.

+0

Ustawiam "model zmiennoprzecinkowy" na "Ścisły (/ fp: ścisły)", a wynik jest taki sam. Czy tęskniłem za czymś tutaj? –

+0

Też to zauważyłem. Próbuję to też rozgryźć. W zoptymalizowanej kompilacji optymalizator składa wszystkie obliczenia. Myślę, że * nie jest to zgodne ze ścisłym zachowaniem zaokrąglania. – Mysticial

+0

W rzeczywistości mój projekt używa C++/CLI w vs2010, więc może to też dotyczy? –

Powiązane problemy