Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Visual Studio debug vs. release build: comparing int and float missmatch

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
like image 691
johannes Avatar asked May 11 '16 12:05

johannes


1 Answers

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.

like image 89
user6320439 Avatar answered Nov 15 '22 19:11

user6320439