0

I have such a program

int a = 100;
float b = 1.05;
printf("%f\n", a * b);
printf("%f\n", 100 * 1.05);

Its output looks like this:

104.999992
105.000000

I understand that `104.99992' is due to floating-point precision issues. But why does the use of direct numbers not result in a loss of accuracy?

velscode
  • 75
  • 3
  • 3
    Well `1.05` is considered a **double**. Try `100 * 1.05f` you should see similar results. – alex01011 Sep 19 '21 at 02:49
  • 1
    Possible duplicate, [What's the use of suffix `f` on float value](https://stackoverflow.com/questions/5026570/whats-the-use-of-suffix-f-on-float-value) – alex01011 Sep 19 '21 at 02:53

1 Answers1

2

a * b uses float arithmetic. 100 * 1.05 uses double arithmetic.

Your C implementation probably uses IEEE-754 binary64 for double and binary32 for float.

1.05 is a double constant. The decimal numeral 1.05 in source text is converted to the nearest representable double value, which is 4728779608739021•2−52 = 1.0500000000000000444089209850062616169452667236328125.

float b = 1.05; converts that value to float. The result of the conversion is the nearest representable float value, which is 4728779393990656•2−52 = 4404019•2−22 = 1.0499999523162841796875.

When b is multiplied by 100 in float arithmetic, the result is the representable float value that is nearest the real-arithmetic result. It is 13762559•2−17 = 104.99999237060546875.

When that is printed with six digits after the decimal point, the result is “104.999992”.

In 100 * 1.05, only double arithmetic is used; there are no float values. When the double 1.0500000000000000444089209850062616169452667236328125 is multiplied by 100, the result is the double nearest the real-arithmetic result. It is 105•20 = 105. When that is printed with six digits after the decimal point, the result is of course “105.000000”.

Summary: There are generally rounding errors in floating-point arithmetic. In float arithmetic, they are easily visible when more than a few digits are printed. In this example with double arithmetic, the rounding errors happened to cancel—the double nearest 1.05 was slightly above 1.05, so the rounding in the conversion rounded up. Then, when that was multiplied by 100, the double nearest the real-arithmetic result was slightly below it, so the rounding in the multiplication rounded down. These effectively canceled, producing 105.

If you execute printf("%f\n", 100*1.05f);, 1.05f will be converted directly to float instead of to a double, and the multiplication will be done with float arithmetic,1 and you will see the same result as for a * b.

Footnote

1 The C standard allows extra precision to be used, but generally you will see the same result here.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312