Casting double to float - compiler bug?

Discussion in 'C Programming' started by Jonathan Fielder, Aug 6, 2003.

  1. Hi,

    My program (below) casts a double (which is in range for a float) to a
    float. As far as I know this should give me the nearest representable
    float, which will loose some precision. I then test for a NAN by comparing
    my float to itself (is this correct?), and I get different behaviour with
    different compilers. Have I done something that is undefined, or is this a
    compiler bug?

    Thanks,

    Jon.

    GCC:

    $ ./a.exe
    *** NOT A NAN ***
    y = 1.56723856925964355469

    MS Visual C++:

    $ ./single
    *** NAN ***
    y = 1.56723856925964360000


    #include <stdio.h>

    int main(void) {
    /* set x to double that is in RANGE for single precision */
    double x = 1.5672385729857;
    /* cast double to float, loosing PRECISION */
    float y = (float) x;

    /* test for bad y - test for NAN */
    if (y != y) {
    printf("*** NAN ***\n\n");
    printf("y = %10.20f\n", y);
    }
    else {
    printf("*** NOT A NAN ***\n\n");
    printf("y = %10.20f\n", y);
    }
    }
     
    Jonathan Fielder, Aug 6, 2003
    #1
    1. Advertising

  2. Jonathan Fielder

    Dan Pop Guest

    In <bgr7lm$vej$> "Jonathan Fielder" <> writes:

    >My program (below) casts a double (which is in range for a float) to a
    >float. As far as I know this should give me the nearest representable
    >float, which will loose some precision. I then test for a NAN by comparing
    >my float to itself (is this correct?), and I get different behaviour with
    >different compilers. Have I done something that is undefined, or is this a
    >compiler bug?


    C89 doesn't specify anything about NANs, but this is not an issue for your
    program, which doesn't involve any NANs, your value being in range for
    both double and float.

    >GCC:
    >
    >$ ./a.exe
    >*** NOT A NAN ***
    >y = 1.56723856925964355469
    >
    >MS Visual C++:
    >
    >$ ./single
    >*** NAN ***
    >y = 1.56723856925964360000
    >
    >
    >#include <stdio.h>
    >
    >int main(void) {
    > /* set x to double that is in RANGE for single precision */
    > double x = 1.5672385729857;
    > /* cast double to float, loosing PRECISION */
    > float y = (float) x;
    >
    > /* test for bad y - test for NAN */
    > if (y != y) {
    > printf("*** NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    > else {
    > printf("*** NOT A NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    >}


    I can see no way this program could execute the if branch. If you're
    x86-literate, have a look at the assembly code generated by the
    compiler. I suspect the compiler has somehow managed to compare the
    value before truncation with the value after truncation and found them
    different (no surprise!).

    You may also want to check the faulty compiler's documentation for an
    option disabling certain illegal floating point optimisations that might
    be enabled by default (a la gcc's -ffloat-store).

    Dan
    --
    Dan Pop
    DESY Zeuthen, RZ group
    Email:
     
    Dan Pop, Aug 6, 2003
    #2
    1. Advertising

  3. On 6 Aug 2003 16:31:21 GMT, (Dan Pop) wrote:

    >In <bgr7lm$vej$> "Jonathan Fielder" <> writes:
    >
    >>My program (below) casts a double (which is in range for a float) to a
    >>float. As far as I know this should give me the nearest representable
    >>float, which will loose some precision. I then test for a NAN by comparing
    >>my float to itself (is this correct?), and I get different behaviour with
    >>different compilers. Have I done something that is undefined, or is this a
    >>compiler bug?

    >
    >C89 doesn't specify anything about NANs, but this is not an issue for your
    >program, which doesn't involve any NANs, your value being in range for
    >both double and float.
    >
    >>GCC:
    >>
    >>$ ./a.exe
    >>*** NOT A NAN ***
    >>y = 1.56723856925964355469
    >>
    >>MS Visual C++:
    >>
    >>$ ./single
    >>*** NAN ***
    >>y = 1.56723856925964360000
    >>
    >>
    >>#include <stdio.h>
    >>
    >>int main(void) {
    >> /* set x to double that is in RANGE for single precision */
    >> double x = 1.5672385729857;
    >> /* cast double to float, loosing PRECISION */
    >> float y = (float) x;
    >>
    >> /* test for bad y - test for NAN */
    >> if (y != y) {
    >> printf("*** NAN ***\n\n");
    >> printf("y = %10.20f\n", y);
    >> }
    >> else {
    >> printf("*** NOT A NAN ***\n\n");
    >> printf("y = %10.20f\n", y);
    >> }
    >>}

    >
    >I can see no way this program could execute the if branch. If you're
    >x86-literate, have a look at the assembly code generated by the
    >compiler. I suspect the compiler has somehow managed to compare the
    >value before truncation with the value after truncation and found them
    >different (no surprise!).
    >
    >You may also want to check the faulty compiler's documentation for an
    >option disabling certain illegal floating point optimisations that might
    >be enabled by default (a la gcc's -ffloat-store).
    >
    >Dan
    >--


    Under MS VC6, if Microsoft extensions are enabled (by default
    (/Ze)), the wrong branch is taken. The comparison seems to be
    made as you say (I'm too lazy to look at the assembly output -
    maybe the OP will want to). Note also that y == x evaluates to
    true in this case.

    Under MS VC6 If Microsoft extensions are disabled (/Za), the
    correct branch is taken.

    (To the OP) It is a well-known problem that x86 processors do not
    cast from greater precision to lesser precision properly by
    default. Floats are 32 bits, doubles are 64 bits, and
    intermediate results are stored in 80 bit floating-point
    registers. Sometimes values are reloaded from memory at
    inappropriate times, such as the case at hand. In essence, y in
    an 80-bit floating-point register (maintaining the value of x) is
    compared with the 32-bit value of y, and they compare not equal.
    If /Za is set, then this behavior is supressed, and the cast is
    performed correctly.

    Regards,
    Bruce Wheeler
     
    Bruce Wheeler, Aug 6, 2003
    #3
  4. Jonathan Fielder

    Tim Prince Guest

    Jonathan Fielder wrote:

    > I then test for a NAN by
    > comparing my float to itself (is this correct?), and I get different
    > behaviour with
    > different compilers.
    >
    > /* test for bad y - test for NAN */
    > if (y != y) {
    > printf("*** NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    > else {
    > printf("*** NOT A NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    > }

    Without disagreeing with other respondents, I'd like to point out that gcc
    is unusual in not evaluating (y != y) with standard optimizations, at
    compile time, by default. If you issue the options -O -ffast-math, it may
    choose to evaluate that expression as 0 at compile time. In your case, it
    will get the same result with evaluation at run time. The C99 standard,
    AFAIK, requires you to use the isnan() function to avoid making this code
    depend on compiler options and implementation. Prior to C99, the question
    was not addressed, other than by gcc conforming to the informed consensus
    of experts.
    I would not be surprised if the result you got with your Microsoft compiler
    depended on the optimization level.
    --
    Tim Prince
     
    Tim Prince, Aug 7, 2003
    #4
  5. Thanks!

    Jon.

    "Jonathan Fielder" <> wrote in message
    news:bgr7lm$vej$...
    > Hi,
    >
    > My program (below) casts a double (which is in range for a float) to a
    > float. As far as I know this should give me the nearest representable
    > float, which will loose some precision. I then test for a NAN by

    comparing
    > my float to itself (is this correct?), and I get different behaviour with
    > different compilers. Have I done something that is undefined, or is this

    a
    > compiler bug?
    >
    > Thanks,
    >
    > Jon.
    >
    > GCC:
    >
    > $ ./a.exe
    > *** NOT A NAN ***
    > y = 1.56723856925964355469
    >
    > MS Visual C++:
    >
    > $ ./single
    > *** NAN ***
    > y = 1.56723856925964360000
    >
    >
    > #include <stdio.h>
    >
    > int main(void) {
    > /* set x to double that is in RANGE for single precision */
    > double x = 1.5672385729857;
    > /* cast double to float, loosing PRECISION */
    > float y = (float) x;
    >
    > /* test for bad y - test for NAN */
    > if (y != y) {
    > printf("*** NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    > else {
    > printf("*** NOT A NAN ***\n\n");
    > printf("y = %10.20f\n", y);
    > }
    > }
    >
    >
    >
    >
     
    Jonathan Fielder, Aug 7, 2003
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Sydex
    Replies:
    12
    Views:
    6,646
    Victor Bazarov
    Feb 17, 2005
  2. bd
    Replies:
    0
    Views:
    663
  3. Bill Reid
    Replies:
    23
    Views:
    620
    Nick Keighley
    Jul 15, 2008
  4. Carsten Fuchs
    Replies:
    45
    Views:
    1,648
    James Kanze
    Oct 8, 2009
  5. news.aon.at
    Replies:
    36
    Views:
    2,204
    Tim Rentsch
    Jan 26, 2012
Loading...

Share This Page