0

In this example, the behaviour of floor differs and I do not understand why:

printf("floor(34000000.535 * 100 + 0.5) : %lf \n", floor(34000000.535 * 100 + 0.5));
printf("floor(33000000.535 * 100 + 0.5) : %lf \n", floor(33000000.535 * 100 + 0.5));

The output for this code is:

floor(34000000.535 * 100 + 0.5) : 3400000053.000000
floor(33000000.535 * 100 + 0.5) : 3300000054.000000

Why does the first result not equal to 3400000054.0 as we could expect?

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
couscousman
  • 94
  • 1
  • 6
  • 1
    Rounding issues of course, use a library for arbitrary precision math (for example gmp) if you need exact calculations. – Ctx Dec 30 '16 at 10:45
  • 2
    Because you're dealing with binary floating-point. – cHao Dec 30 '16 at 10:45
  • @cHao Note that even with _decimal_ [floating point](https://en.wikipedia.org/wiki/Decimal64_floating-point_format), issues like this can occur with values near the precision limits of the format. Such is the properties of floating point arithmetic, in any base. It is certainly more common with decimal text and binary `double`. – chux - Reinstate Monica Dec 30 '16 at 12:08

2 Answers2

3

double in C does not represent every possible number that can be expressed in text.

double can typically represent about 264 different numbers. Neither 34000000.535 nor 33000000.535 are in that set when double is encoded as a binary floating point number. Instead the closest representable number is used.

Text             34000000.535
closest double   34000000.534999996423...
Text             33000000.535
closest double   33000000.535000000149...

With double as a binary floating point number, multiplying by a non-power-of-2, like 100.0, can introduce additional rounding differences. Yet in these cases, it still results in products, one just above xxx.5 and another below.

Adding 0.5, a simple power of 2, does not incurring rounding issues as the value is not extreme compared to 3x00000053.5.

Seeing intermediate results to higher print precision well shows the typical step-by-step process.

#include <stdio.h>
#include <float.h>
#include <math.h>

 void fma_test(double a, double b, double c) {
   int n = DBL_DIG + 3;
   printf("a b c      %.*e %.*e %.*e\n", n, a, n, b, n, c);
   printf("a*b        %.*e\n", n, a*b);
   printf("a*b+c      %.*e\n", n, a*b+c);
   printf("a*b+c      %.*e\n", n, floor(a*b+c));
   puts("");
 }

int main(void) {
  fma_test(34000000.535, 100, 0.5);
  fma_test(33000000.535, 100, 0.5);
}

Output

a b c      3.400000053499999642e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b        3.400000053499999523e+09
a*b+c      3.400000053999999523e+09
a*b+c      3.400000053000000000e+09

a b c      3.300000053500000015e+07 1.000000000000000000e+02 5.000000000000000000e-01
a*b        3.300000053500000000e+09
a*b+c      3.300000054000000000e+09
a*b+c      3.300000054000000000e+09

The issue is more complex then this simple answers as various platforms can 1) use higher precision math like long double or 2) rarely, use a decimal floating point double. So code's results may vary.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • chux, you made a mistake by saying that there are 2^64 different numbers represented. In reality, there are many less. Because there is the exponent part inside those 64, the same kind of representation as in the case of `float` that I analysed in my answer. A compiler can represent the number 100 as 10e2 or 100e1. The exponent part has no `property` about how a compiler should set it. See my answer that prints how a `double`/`long double`/`float` are represented. So when you write x=100 you cannot be sure neither what representation the compiler will give, nor the floating point hardware – alinsoar Dec 31 '16 at 12:09
  • @alinsoar This answer did not say there are 2^64 different numbers. This answer, before your unnecessary edit, said "about 2^64 different numbers". In reality there are **not** many less values. A chunk of the 2^64 different bit patterns are Not-A-Numbers which only reduces the value pattern count less than 0.1%. Your exponent discussion of printing 100 as 10e2 or 100e1, still just one of the count of the 2^64 patterns, is irrelevant. Do not edit this answer - that edit and comment intent misleads the correct intent. – chux - Reinstate Monica Dec 31 '16 at 14:25
  • you could have used "less than", as it is more correct than "about". – alinsoar Dec 31 '16 at 16:39
  • @alinsoar The difference between "about 2^64 different numbers" and "less than 2^64 different numbers" is insignificant relative to OP's issue. The "about" has the advantage of indicating closeness, "less than" does not. Could has used "nearly 2^64 different numbers" to convey both thoughts, but again, it is not core to OP issue. – chux - Reinstate Monica Dec 31 '16 at 22:52
0

Question has been already answered here.

In basic float numbers are just approximation. If we have program like this:

float a = 0.2 + 0.3;
float b = 0.25 + 0.25;

if (a == b) {
    //might happen
}
if (a != b) {
    // also might happen
}

The only guaranteed thing is that a-b is relatively small.

Community
  • 1
  • 1
Peter Hrvola
  • 9
  • 1
  • 3