My code is below:
int main(int argc, char *argv[])
{
double f = 18.40;
printf("%d\n", (int)(10 * f));
return 0;
}
The result is 184 in VC6.0, while the result in Codeblock is 183. Why?
My code is below:
int main(int argc, char *argv[])
{
double f = 18.40;
printf("%d\n", (int)(10 * f));
return 0;
}
The result is 184 in VC6.0, while the result in Codeblock is 183. Why?
The reason for this is that GCC tries to make the code backward compatible with older architectures of the CPU as much as possible, while MSVC tries to take advantage of the newer futures of the architecture.
The code generated by MSVC multiplies the two numbers, 10.0 × 18.40:
and then call a function named
__ftol2_sse
, inside this function it converts the result to integer using some instruction namedcvttsd2si
:This instruction,
cvttsd2si
, is according to this page:it basically converts the double into integer. This instruction is part of instruction set called SSE2 which is introduced with Intel Pentium 4.
GCC doesn't uses this instructions set by default and tries to do it with the available instructions from i386:
if you want GCC to use
cvttsd2si
you need to tell it to use the futures available from SSE2 by compiling with the flag-msse2
, but also this means that some people who still using older computers won't be able to run this program. See here Intel 386 and AMD x86-64 Options for more options.So after compiling with
-msse2
it will usecvttsd2si
to convert the result to 32 bit integer:now both MSVC and GCC should give the same number:
The point is, that
0.4
is2/5
. Fractions with anything but a power of two in the denominator are not exactly representable in floating point numbers, much like 1/3 is not exactly representable as a decimal number. Thus, your compiler has to choose a nearby, representable number, with the result that10*18.4
is not precisely184
, but183.999
...Now, everything depends on the rounding mode employed when your float is converted to an integer. With round to nearest or round to infinity, you get
184
, with round to zero or round to minus infinity you get183
.Codeblocks compiler has probably something like 18.39999999999 as the floating point value. I think you should round if you want a consistent result.
Floating point calculations are implemented differently by different compilers and different architectures. Even the same compiler can have different modes of operation that will yield different results.
For example, if I take your program and my installation of gcc (MinGW, 4.6.2) and compile like this:
then the output is, as your report, 183.
However, if I compile like this:
then the output is 184.
If you really want to understand the differences you need to specify precise compiler versions, and specify which options you are passing to the compiler.
More fundamentally, you should be aware that the value
18.4
cannot be represented exactly as a binary floating point value. The closest representable double precision value to18.4
is:So I suspect that you are reasoning that the correct output from your program is
184
. But I suspect that reasoning is flawed and fails to account for representability, rounding, etc. issues.