Like Tree1Likes
  • 1 Post By laserlight

verify MinGW issue

This is a discussion on verify MinGW issue within the C Programming forums, part of the General Programming Boards category; This is more of can you verify my results posting. I primarily use TDM-GCC ( TDM-GCC ) for my needs ...

  1. #1
    Registered User
    Join Date
    Mar 2013
    Posts
    33

    verify MinGW issue

    This is more of can you verify my results posting.


    I primarily use TDM-GCC ( TDM-GCC ) for my needs but I was interested in this
    distro package from: MinGW Distro - nuwen.net


    I found different results from the snippit below.
    An inquiry suggested I contact the MinGW group.


    I then tried using a couple different MinGW versions up to and including the new 4.8.0
    They all gave the same results -> 1266


    I also tested as:
    a c++ example using cl from the Win7.1 sdk
    a c++ example using the free Borland 5.5
    a BASIC version using PowerBASIC and FreeBasic.
    PellesC
    tcc


    All displayed 1267 except for Borland and MinGW


    James






    source:

    Code:
    //***************************************************************
    #include <stdio.h>
    
    
    
    
    int     foo (double);
    int     main (int,char**);
    
    
    
    
    int foo (double d)
    {
      printf("%s% .15G\n","d = ",(double)d);
      return d*100;
    }
    
    
    
    
    int main (int argc,char** argv)
    {
      int      rv={0};
      rv= foo( 12.67);
      printf("%s% d\n","rv = ",(int)rv);
      return 0;
    }
    //***************************************************************
    This is the result of compiling and running using distro mingw-9.6
    Code:
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>\Mingw\set_distro_paths
    
    
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>gcc --version
    gcc (GCC) 4.7.2
    Copyright (C) 2012 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    
    
    
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>gcc rv.c -orv.exe
    
    
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>rv
    d =  12.67
    rv =  1266
    *********************************************************************************

    this is the result from MinGWTDM
    Code:
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>%MINGW%\bin\gcc --version
    gcc (tdm64-1) 4.7.1
    Copyright (C) 2012 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    
    
    
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>%MINGW%\bin\gcc rv.c -orv.exe -m32
    
    
    C:\bc9Adp\RadAsm\Bc9\Examples\bc9CppExamples>rv
    d =  12.67
    rv =  1267

  2. #2
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,976
    I got 1266 with this program:
    Code:
    #include <stdio.h>
    
    int main(void)
    {
        double value = 12.67;
        int result = (int)(value * 100);
        printf("%d\n", result);
        return 0;
    }
    compiled on the canonical MinGW port of gcc 4.6.2 with no options for optimisation. Compiled with -O2, and got 1267 (probably due to constant propagation). Looks like just a case of floating point inaccuracy.
    stahta01 likes this.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    5,871
    .67 is an infinite series in binary (base 2). Depending on the precision of the floating point representation (i.e. number of bits used to represent the mantissa) multiplying by 100 may yield a value that is either slightly greater than 67, or slightly less. If the result of the multiplication is slightly greater than 67, it will be rounded down to 67 when converted to an int. Otherwise, if the result of the multiplication is slightly less than 67, converting to an int will cause rounding down (to 66).

    What happens is formally implementation-defined. Both results are reasonable within limits of floating point accuracy and precision.
    Right 98% of the time, and don't care about the other 3%.

  4. #4
    Registered User
    Join Date
    Mar 2013
    Posts
    33
    @grumpy -> excellent explanation thank you.

    Now if I change d to a float instead of a double, 1267 is displayed across the board with all compilers I tried.

    James

  5. #5
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    20,976
    Quote Originally Posted by jcfuller
    Now if I change d to a float instead of a double, 1267 is displayed across the board with all compilers I tried.
    Of course, the calculations are still subject to floating point inaccuracy.
    C + C++ Compiler: MinGW port of GCC
    Version Control System: Bazaar

    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  6. #6
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Write out 12.67 in binary (hint: you may need a long piece of paper).

    Now truncate it at some random point that gives you enough accuracy. Every compiler can choose a different point so long as they are within the specification (which DOESN'T tell them where to truncate, just where they *CAN'T*, effectively - i.e. where it would lose too much accuracy). Now do your multiplication, rounding, whatever you want on all those different possible answers.

    Thus different compilers will give you different answers and even things like the order of operations you do can really mess with the numbers. But NOT outside of their margins of error anyway. Doubles and floats will both truncate at different points in different compilers, on different architectures, and so long as they obey the minimum requirements, there's NOTHING saying they have to give the same answer.

    And your code should always account for that. That's the point. You will not get standardised behaviour of a float/double across every platform. Because the specs say that's basically implementation-defined and so long as it's within a certain range, it's fine. That's as good a guarantee as you get with floating point in C.

    Yeah, it would be lovely to have some consistency, and yeah you can sometimes think you've found consistency by tweaking the way you do things. But, basically, unless you want to use a FIXED-POINT library, or write your own floating point library that you use cross-platform, you won't be able to get the guarantees you are after.

    What you did, and the answers you got, are all perfectly valid. They don't NEED to be the same, in order to call themselves C compilers. And that situation has been the same since C was invented!

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  7. #7
    Registered User
    Join Date
    Mar 2013
    Posts
    33
    Thanks everyone.


    This is my latest test piece. When compiled with the newest 32bit gcc 4.8.0 only the first one displays 1266


    James


    Code:
    #include <stdio.h>
    #include <math.h>
    int     foo (double);
    int     main (int,char**);
    
    
    int foo (double d)
    {
      printf("%s% .15G\n","d = ",(double)d);
    return (d*100);      // 1266
    //return ceil(d*100);  // 1267
    //return floor(d*100); // 1267
    //return trunc(d*100); // 1267
    //return round(d*100);   // 1267
    }
    
    
    int main (int argc,char** argv)
    {
      int      rv={0};
      double d =12.67;
      rv= foo( d);
      printf("%s% d\n","rv = ",(int)rv);
      return 0;
    }

  8. #8
    Registered User
    Join Date
    Jun 2005
    Posts
    5,871
    Quote Originally Posted by jcfuller View Post
    This is my latest test piece. When compiled with the newest 32bit gcc 4.8.0 only the first one displays 1266
    If you compile/build it with a different compiler, you may well get different results. You may even get different results if you update to a newer version of gcc, or select some different compilation options.

    And, if you use a value other than 12.67, you may well get results that may be rounded either up or down, even with gcc 4.8.0.
    Right 98% of the time, and don't care about the other 3%.

  9. #9
    Registered User
    Join Date
    Mar 2010
    Posts
    531
    Quote Originally Posted by jcfuller View Post
    Now if I change d to a float instead of a double, 1267 is displayed across the board with all compilers I tried.
    I tried your last test -- on GCC 4.7.2 (x86_64-linux-gnu, Ubuntu) it gives me 1267 for doubles and floats. If I change to "long double" it gives me 1267 for 12.67L but 1266 for 12.67 (i.e. assigning a double constant to a long double variable).

    Although floating point types can and will drop accuracy on the floor, this example makes it look worse than it is. If you ask printf for 50 digits instead of 15 it looks more forgivable.

    Code:
    d =  12.66999999999999992894572642398998141288757324218750
    rv =  1266
    
    d =  12.66999999999999992894572642398998141288757324218750
    rv =  1267

  10. #10
    Registered User
    Join Date
    Mar 2013
    Posts
    33
    Thank you all for your responses.
    I do have a better understanding of the what is happening.
    I also took the question to another venue I frequent :
    fpu example

    I ran into this scenario while working on example code for bc9: bc9 home and got a bit carried away.

    Most users probably have even less c/c++ experience that I do (which is none too great) so I was looking for a way (if possible) to return the same value for all compilers supported by bc9.

    James

  11. #11
    Registered User
    Join Date
    Mar 2013
    Posts
    33
    I believe I found the answer thanks to MichaelW on the masm32 forum from the link in the last msg.
    I am surprised no one here was aware of this???

    From MinGw float.h


    MSVCRT.dll _fpreset initializes the control register to 0x27f,
    the status register to zero and the tag word to 0FFFFh.
    This differs from asm instruction finit/fninit which set control
    word to 0x37f (64 bit mantissa precison rather than 53 bit).
    By default, the mingw version of _fpreset sets fp control as
    per fninit. To use the MSVCRT.dll _fpreset, include CRT_fp8.o when
    building your application.


    James

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. MinGW linking issue
    By ascen in forum Windows Programming
    Replies: 1
    Last Post: 03-31-2010, 04:26 AM
  2. MinGW Compiling Issue
    By gesangbaer in forum C++ Programming
    Replies: 3
    Last Post: 12-10-2009, 08:41 PM
  3. Can someone verify this code?
    By Hunter2 in forum Networking/Device Communication
    Replies: 3
    Last Post: 06-29-2004, 10:28 PM
  4. verify EOF
    By threahdead in forum C Programming
    Replies: 1
    Last Post: 10-11-2002, 07:49 AM
  5. verify input
    By Unregistered in forum C Programming
    Replies: 5
    Last Post: 05-23-2002, 05:38 PM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21