I’m using GCC to compile a program which adds floats, longs, ints and chars. When it runs, the result is bad. The following program unexpectedly prints the value of 34032.101562.
Recompiling with a Microsoft compiler gives the right result.
#include <stdio.h>
int main (void) {
const char val_c = 10;
const int val_i = 20;
const long val_l = 34000;
const float val_f = 2.1;
float result;
result = val_c + val_i + val_l + val_f;
printf("%f\n", result);
return 0;
}
What do you think the “right result” is? I’m guessing that you believe it is 34032.1. It isn’t.
2.1 is not representable as a
float, soval_finstead is initialized with the closest representablefloatvalue. In binary, 2.1 is:a
floathas 24 binary digits, so the value ofval_fin binary is:The expression
resultat = val_c + val_i + val_l + val_fcomputes34030 + val_f, which is evaluated in single-precision and causes another rounding to occur.In decimal, this result is exactly 34032.1015625. Because the
%fformat prints 6 digits after the decimal point (unless specified otherwise), this is rounded again, and printf prints34032.101562.Now, why do you not get this result when you compile with MSVC? The C and C++ standard allow floating-point calculations to be carried out in a wider type if the compiler chooses to do so. MSVC does this with your calculation, which means that the result of
34030 + val_fis not rounded before being passed toprintf. In that case, the exact floating-point value being printed is 34032.099999999991268850862979888916015625, which is rounded to 34032.1 by printf.Why don’t all compilers do what MSVC does? A few reasons. First, it’s slower on some processors. Second, and more importantly, although it can give more accurate answers, the programmer cannot depend on that — seemingly unrelated code changes can cause the answer to change in the presence of this behavior. Because of this, carrying extra precision often causes more problems than it solves.