By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,454 Members | 3,133 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,454 IT Pros & Developers. It's quick & easy.

Casting double to float - compiler bug?

P: n/a
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);
}
}


Nov 13 '05 #1
Share this Question
Share on Google+
4 Replies


P: n/a
In <bg**********@sabina.mathworks.co.uk> "Jonathan Fielder" <jf******@mathworks.com> 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: Da*****@ifh.de
Nov 13 '05 #2

P: n/a
On 6 Aug 2003 16:31:21 GMT, Da*****@cern.ch (Dan Pop) wrote:
In <bg**********@sabina.mathworks.co.uk> "Jonathan Fielder" <jf******@mathworks.com> 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

Nov 13 '05 #3

P: n/a
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
Nov 13 '05 #4

P: n/a
Thanks!

Jon.

"Jonathan Fielder" <jf******@mathworks.com> wrote in message
news:bg**********@sabina.mathworks.co.uk...
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);
}
}

Nov 13 '05 #5

This discussion thread is closed

Replies have been disabled for this discussion.