in reply to Re: [Win32, C, and way OT] C floats, doubles, and their equivalence
in thread [Win32, C, and way OT] C floats, doubles, and their equivalence

I think your detailed investigation demonstrates why the code I posted in repsonse to creamygoodness's post behaves the way it does.

After much poking and scratching and re-reading of suggestions that have been kindly and thoughtfully presented here, I've eventually come up with using this approach in the PDL code:
#include <stdio.h> #if defined _MSC_VER && _MSC_VER < 1400 #pragma optimize("", off) #endif int main(void) { #if defined _MSC_VER && _MSC_VER < 1400 double nv = 2.0 / 3; float foo = 2.0 / 3; float dummy = (float)nv; if(foo == dummy) printf("True "); else printf("False "); #else double nv = 2.0 / 3; float foo = 2.0 / 3; if(foo == (float)nv) printf("True "); else printf("False "); #endif return 0; }
It seems to be doing the right thing with all of my compilers.
I don't think that C script needs to have the optimization turned off - the creation of the dummy variable is alone sufficient to get the behaviour I'm after. But for some reason, in the PDL code, creation of the dummy variable is *not*, by itself, sufficient - optimization also needs to be disabled. (I turn it off for the setvaltobad functions, then turn it back on again.)

Thanks to *all* who replied.

Cheers,
Rob
  • Comment on Re^2: [Win32, C, and way OT] C floats, doubles, and their equivalence
  • Download Code

Replies are listed 'Best First'.
Re^3: [Win32, C, and way OT] C floats, doubles, and their equivalence
by BrowserUk (Patriarch) on Jul 19, 2009 at 07:28 UTC
    But for some reason, in the PDL code, creation of the dummy variable is *not*, by itself, sufficient - optimization also needs to be disabled. (I turn it off for the setvaltobad functions, then turn it back on again.)

    That's why I moved the temp var and comparison into a separate function; it forces the compiler to use the temp value from memory for the comparison:

    ; 5 : return s == tmp ? 1 : 0; fld DWORD PTR _s$[ebp] fcomp DWORD PTR _tmp$[ebp] fnstsw ax test ah, 68 ; 00000044H jp SHORT $L809

    The problem with the test script is that with optimisations enabled, the newer compiler is able to reduce the whole script to a simple printf( "False" ); printf( "True" ); return 0; (even with the use of the sub) as everything is known at compile time:

    ; Listing generated by Microsoft (R) Optimizing Compiler Version 15.00 +.30729.01 TITLE C:\test\float.c .686P .XMM include listing.inc .model flat INCLUDELIB LIBCMT INCLUDELIB OLDNAMES _DATA SEGMENT $SG2527 DB 'True ', 00H ORG $+2 $SG2529 DB 'False ', 00H ORG $+1 $SG2531 DB 'True', 0aH, 00H ORG $+2 $SG2533 DB 'False', 0aH, 00H _DATA ENDS PUBLIC _cmpFsFd EXTRN __fltused:DWORD ; Function compile flags: /Ogtpy ; File c:\test\float.c ; COMDAT _cmpFsFd _TEXT SEGMENT tv135 = 8 ; size = 4 _s$ = 8 ; size = 4 _d$ = 12 ; size = 8 _cmpFsFd PROC ; COMDAT ; 4 : float tmp = (float)d; ; 5 : return s == tmp ? 1 : 0; fld DWORD PTR _s$[esp-4] fld QWORD PTR _d$[esp-4] fstp DWORD PTR tv135[esp-4] fld DWORD PTR tv135[esp-4] fucompp fnstsw ax test ah, 68 ; 00000044H jp SHORT $LN3@cmpFsFd mov eax, 1 ; 6 : } ret 0 $LN3@cmpFsFd: ; 4 : float tmp = (float)d; ; 5 : return s == tmp ? 1 : 0; xor eax, eax ; 6 : } ret 0 _cmpFsFd ENDP _TEXT ENDS PUBLIC _main EXTRN _printf:PROC ; Function compile flags: /Ogtpy _TEXT SEGMENT _main PROC ; 11 : double nv = 2.0 / 3; ## ; 12 : float foo = 2.0 / 3; ## All this and ... ; 13 : ; 14 : if( foo == nv ) printf("True "); ## ; 15 : else printf("False "); push OFFSET $SG2529 call _printf ; 16 : ; 17 : if( cmpFsFd( foo, nv ) ) printf("True\n"); ## this are op +timised away! push OFFSET $SG2531 call _printf add esp, 8 ; 18 : else printf("False\n"); ; 19 : ; 20 : return 0; xor eax, eax ; 21 : } ret 0 _main ENDP _TEXT ENDS END

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      That's why I moved the temp var and comparison into a separate function

      Having a separate function is appealing, but not so straightforward to implement. It would be fine if we had an xs file to fiddle with, but the fact that the source file to be amended is a pd file (not an xs file) adds some complexity to the problem. I think it is possible to use the "separate function" approach - though it's actually "separate functions" (plural), as the templating dictates that we'll need separate functions to handle each of the different data types (ie byte, short, long, long long, double - not just float). There's also the issue of the second arg that gets supplied to the "separate function" - it could be a UV or an IV, not necessarily an NV, so we need to accommodate that as well (probably not difficult).

      It's a much simpler solution if one instead just adds a dummy variable and turns off optimization - which seems to work quite well.

      Cheers,
      Rob