Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unexpected value printed when using %.1f

I'm trying to display floats to just one decimal point. I'm getting unexpected results as follows:

Code:

float a = 1.25;
float b = 1.35;

NSLog(@"1.25 -> %.1f\n1.35 -> %.1f",a,b);

Output:

1.25 -> 1.2

1.35 -> 1.4

Expected output, either:

1.25 -> 1.3

1.35 -> 1.4

or:

1.25 -> 1.2

1.35 -> 1.3

Is this simply due to the internal conversion between binary and decimal? If so, how do I get the expected behaviour?

I'm using Xcode 4.6.

edit: Okay, thanks to TonyK and H2CO3 it's due to the binary representation of decimals.

float a = 1.25;
float b = 1.35;
NSLog(@"1.25 -> %.30f\n1.35 -> %.30f",a,b);

1.25 -> 1.250000000000000000000000000000

1.35 -> 1.350000000000000088817841970013

Lots of good info, but as far as I can see no one has approached the second question: How do I get the expected behaviour?

Rounding numbers in Objective-C is a quite different question.

like image 337
putridp Avatar asked Feb 13 '26 00:02

putridp


2 Answers

1.35 is 27/20, which in binary is

1.01 0110 0110 0110 0110 0110 0110....

A float has a 23-bit mantissa on most systems (not counting the implied leading 1.), so this gets rounded up to

1.01 0110 0110 0110 0110 0110 1

(because 0110 is unambiguously greater than half of 1000). So it's strictly greater than 1.35 by the time printf sees it. Hence 1.4.

As for 1.25, this is exactly representable in binary as

1.01

So printf sees its exact value. But how should it round 1.25? We were taught in school to round 5 up to 10. But most modern systems use a default rounding mode called "round to even" at the hardware level, because it lessens the effect of cumulative rounding errors. This means that when a number is exactly between the two nearest candidates for rounding, it gets rounded to the even candidate.

So it seems that print is using "round to even" for decimal output! I checked this hypothesis at this ideone link, and indeed 1.75 gets rounded up, to 1.8. This is a surprise to me, but not a huge one.

like image 161
TonyK Avatar answered Feb 15 '26 12:02

TonyK


That's because floating-point numbers aren't exact. %.1f prints the number rounded to one decimal place, it seems, however, that 1.35 can't be exactly represented as 1.2500000, instead it's a slightly smaller number that can be.

Read about this behavior here: What every computer scientist should know about floating-point numbers.