4
printf("%.1f, %.2f", 1.45, 1.445);

output

1.4, 1.45

1.45 is sliced but 1.445 is rounded.

I found this, Why printf round floating point numbers? Which explained the specification recommands to round the float.

Edit: I tested it with VS2017 (in a C++ project) and Dev-C.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
Zhang
  • 3,030
  • 2
  • 14
  • 31
  • 2
    Assuming your implementation uses IEEE-754 floats like many do, neither value has an exact representation. So the constant you write as `1.4` in the source code gets compiled to a double value which is close to, but not equal to, `1.4`. Which way it rounds afterwards is happenstance. – dxiv Dec 27 '20 at 04:51
  • 1
    Try `printf("%.55f\n%.55f\n", 1.45, 1.445);` to see what the actual numbers are. – user3386109 Dec 27 '20 at 04:53
  • 1
    The question is in the topic name – user2233706 Dec 27 '20 at 04:59

2 Answers2

8

[Edited: I didn't originally print them to quite ridiculous enough levels of precision, so the answer gave incorrect reasoning behind the result.]

If you print them out to ridiculous levels of precision, the truth comes out:

#include <stdio.h>
printf("%20.20f, %20.20f", 1.45, 1.445);

Result:

1.44999999999999995559, 1.44500000000000006217

So, as converted, 1.45 ends up ever so minutely smaller than 1.45, and 1.445 ends up every so slightly greater than 1.445.

So, of course, when we round 1.45, it rounds down, but when we round 1.445, it rounds upward.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Minor: width not needed. `"%.20f"` is enough to demo your good point. – chux - Reinstate Monica Dec 27 '20 at 05:03
  • Thanks, I had the same assumption. But I debugged the double value only with 7 or 8 decimal places and didn't see the "truth", haha. – Zhang Dec 27 '20 at 05:09
  • @Zhang: 7 or 8 would be about enough to see the problem for a `float`, but the decimal precision of a `double` is normally around 16 places, so we'd expect everything to look "perfect" out to 8 places (and well beyond). On the other hand, there's no way to directly print out a `float` with `printf`--if you try to pass a `float`, it'll be promoted to `double` before it gets to `printf` (and this extra level of conversion can lead to even more confusion in a few rare cases). – Jerry Coffin Dec 27 '20 at 05:11
2

double encodes about 264 different values exactly.

Neither 1.45 nor 1.445 are in that large set of 264 values as those decimal values cannot be represented as a dyadic rational values: some integer times a power of 2.

Instead of 1.45, 1.445, nearby values are used:

 1.45  --> 6530219459687219 * 2^-52 or about 1.449999999999999955591079... 
 1.445 --> 6507701461550367 * 2^-52 or about 1.445000000000000062172489...  or 

OP's printf() performed a good job and rounded those values correctly.

printf("%.1f\n%.2f", 1.45, 1.445);
1.4     
1.45
chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256