Have a look at this example:
#include <stdio.h>
int main() {
int i= 16777217;
float f = 16777216.0;
float g = i;
if( i == f )
printf("eq\n");
else
printf("neq\n");
if( g == f )
printf("eq\n");
else
printf("neq\n");
return 0;
}
which, using Visual Studio 2010 C++ (VS) in release mode, gcc, or g++ (4.9.2), has the output
eq
eq
which is reasonable to me: During the first comparison, i
is implicitly converted to a float where the significant bit in the mantissa is truncated. Thus, both i
and f
have the same bit pattern which compares to equality. In the second if
the same conversion applies but was already performed when defining and initializing g
.
However, using VS in debug mode, the result is
neq
eq
It seems, the implicit conversion during comparison in the first if
(as part of the usual arithmetic conversions in C and C++) is not applied. Is this true? Is there a VS-mechanism which prevents such false positives in comparing floats and ints (conversion to int/float with more precision)? According to MSDN VS C++ follows the standard.
I have checked the bit representation with this function. For all compilers it yields to
i = 00000001000000000000000000000001
f = 01001011100000000000000000000000
g = 01001011100000000000000000000000
float.h
on VS states #define FLT_MANT_DIG 24
so the described truncation issue should hold as well.
I compiled all on the same machine (Intel i5-3570K) but for VS in a virtual box. Compiling with VS on another machine also prints neq/eq
.
EDIT: assembler code attached
differences_debug.asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
TITLE c:\Users\user\documents\visual studio 2010\Projects\differences\differences\differences.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB MSVCRTD
INCLUDELIB OLDNAMES
PUBLIC ??_C@_04LMPLCMBC@neq?6?$AA@ ; `string'
PUBLIC ??_C@_03HNJPMNDP@eq?6?$AA@ ; `string'
PUBLIC __real@4b800000
PUBLIC _wmain
EXTRN __imp__printf:PROC
EXTRN __fltused:DWORD
EXTRN __RTC_CheckEsp:PROC
EXTRN __RTC_Shutdown:PROC
EXTRN __RTC_InitBase:PROC
; COMDAT ??_C@_04LMPLCMBC@neq?6?$AA@
; File c:\users\user\documents\visual studio 2010\projects\differences\differences\differences.cpp
CONST SEGMENT
??_C@_04LMPLCMBC@neq?6?$AA@ DB 'neq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT ??_C@_03HNJPMNDP@eq?6?$AA@
CONST SEGMENT
??_C@_03HNJPMNDP@eq?6?$AA@ DB 'eq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT __real@4b800000
CONST SEGMENT
__real@4b800000 DD 04b800000r ; 1.67772e+007
CONST ENDS
; COMDAT rtc$TMZ
rtc$TMZ SEGMENT
__RTC_Shutdown.rtc$TMZ DD FLAT:__RTC_Shutdown
rtc$TMZ ENDS
; COMDAT rtc$IMZ
rtc$IMZ SEGMENT
__RTC_InitBase.rtc$IMZ DD FLAT:__RTC_InitBase
; Function compile flags: /Odtp /RTCsu /ZI
rtc$IMZ ENDS
; COMDAT _wmain
_TEXT SEGMENT
_g$ = -32 ; size = 4
_f$ = -20 ; size = 4
_i$ = -8 ; size = 4
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_wmain PROC ; COMDAT
; Line 7
push ebp
mov ebp, esp
sub esp, 228 ; 000000e4H
push ebx
push esi
push edi
lea edi, DWORD PTR [ebp-228]
mov ecx, 57 ; 00000039H
mov eax, -858993460 ; ccccccccH
rep stosd
; Line 8
mov DWORD PTR _i$[ebp], 16777217 ; 01000001H
; Line 9
fld DWORD PTR __real@4b800000
fstp DWORD PTR _f$[ebp]
; Line 10
fild DWORD PTR _i$[ebp]
fstp DWORD PTR _g$[ebp]
; Line 13
fild DWORD PTR _i$[ebp]
fld DWORD PTR _f$[ebp]
fucompp
fnstsw ax
test ah, 68 ; 00000044H
jp SHORT $LN4@wmain
; Line 14
mov esi, esp
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
; Line 15
jmp SHORT $LN3@wmain
$LN4@wmain:
; Line 16
mov esi, esp
push OFFSET ??_C@_04LMPLCMBC@neq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
$LN3@wmain:
; Line 19
fld DWORD PTR _g$[ebp]
fld DWORD PTR _f$[ebp]
fucompp
fnstsw ax
test ah, 68 ; 00000044H
jp SHORT $LN2@wmain
; Line 20
mov esi, esp
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
; Line 21
jmp SHORT $LN1@wmain
$LN2@wmain:
; Line 22
mov esi, esp
push OFFSET ??_C@_04LMPLCMBC@neq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
cmp esi, esp
call __RTC_CheckEsp
$LN1@wmain:
; Line 24
xor eax, eax
; Line 26
pop edi
pop esi
pop ebx
add esp, 228 ; 000000e4H
cmp ebp, esp
call __RTC_CheckEsp
mov esp, ebp
pop ebp
ret 0
_wmain ENDP
_TEXT ENDS
END
differences_release.asm
; Listing generated by Microsoft (R) Optimizing Compiler Version 16.00.30319.01
TITLE c:\Users\user\documents\visual studio 2010\Projects\differences\differences\differences.cpp
.686P
.XMM
include listing.inc
.model flat
INCLUDELIB OLDNAMES
PUBLIC ??_C@_03HNJPMNDP@eq?6?$AA@ ; `string'
PUBLIC ??_C@_04LMPLCMBC@neq?6?$AA@ ; `string'
EXTRN @__security_check_cookie@4:PROC
EXTRN __imp__printf:PROC
; COMDAT ??_C@_04LMPLCMBC@neq?6?$AA@
CONST SEGMENT
??_C@_04LMPLCMBC@neq?6?$AA@ DB 'neq', 0aH, 00H ; `string'
CONST ENDS
; COMDAT ??_C@_03HNJPMNDP@eq?6?$AA@
CONST SEGMENT
??_C@_03HNJPMNDP@eq?6?$AA@ DB 'eq', 0aH, 00H ; `string'
CONST ENDS
PUBLIC _wmain
EXTRN __fltused:DWORD
; Function compile flags: /Ogtp
; COMDAT _wmain
_TEXT SEGMENT
_argc$ = 8 ; size = 4
_argv$ = 12 ; size = 4
_wmain PROC ; COMDAT
; File c:\users\user\documents\visual studio 2010\projects\differences\differences\differences.cpp
; Line 7
push esi
; Line 14
mov esi, DWORD PTR __imp__printf
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call esi
; Line 20
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call esi
add esp, 8
; Line 24
xor eax, eax
pop esi
; Line 26
ret 0
_wmain ENDP
_TEXT ENDS
END
If we demangle the release ASM:
; Line 14
push OFFSET ??_C@_03HNJPMNDP@eq?6?$AA@
call DWORD PTR __imp__printf
add esp, 4
; Line 18
xor eax, eax
; Line 20
ret 0
It's just printing eq
and exiting, which suggests that the floating comparison is just completely optimized out. For the debug assembly, we see it using fld
and fild
instructions:
; Line 9
fld DWORD PTR __real@4b800000
fstp DWORD PTR _f$[ebp]
; Line 10
fild DWORD PTR _i$[ebp]
fstp DWORD PTR _g$[ebp]
; Line 13
fild DWORD PTR _i$[ebp]
These are IA32
instructions which is the default architecture used in Visual Studio 2010. I suspect that you use /arch:SSE2
instead you will get different results.
Hans Passant's comment essentially confirms what I just said.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With