11

I am testing two different implementations of printf on my system: printf (GNU coreutils) 8.26, and the version bundled with zsh 5.3.1. I am testing how half numbers are rounded, i.e. for 1.5, 2.5, 3.5, … 9.5.

$ for i in {1..9}; do /usr/bin/printf '%.0f\n' "${i}.5"; done
2
2
4
4
6
6
8
8
10
$ for i in {1..9}; do printf '%.0f\n' "${i}.5"; done
2
2
4
4
6
6
8
8
10

Here, both clearly round half to even. However, when I test rounding to the first decimal place, things get confusing. That is, I'm testing for 1.15, 1.25, 1.35, … 1.95.

$ for i in {1..9}; do /usr/bin/printf '%.1f\n' "1.${i}5"; done
1.1
1.2
1.4
1.5
1.5
1.6
1.8
1.9
2.0
$ for i in {1..9}; do printf '%.1f\n' "1.${i}5"; done
1.1
1.2
1.4
1.4
1.6
1.6
1.8
1.9
1.9

Both implementations do it differently, and I can't see any clear pattern in either. How do these two printfs round halves to the first decimal place?

19

GNU printf uses long double while zsh uses regular doubles. The rounding behaviour you see is because (say) 1.45 can't be represented as a sum of powers of 2, which is how IEEE 754 floating-point representation works, and the nearest approximation varies according to the precision. It's slightly more (with 80 bits) or less (with 64 bits), thus rounding up or down as you see.

As ever, if you care about accurate human-level representation and rounding, don't use floating-point.

  • 1
    Just a note that x.25 and x.75 (for suitably small x) do have exact binary representations, unlike the others. – Toby Speight Feb 21 '17 at 16:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.