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 printf
s round halves to the first decimal place?
Best Answer
GNU printf uses
long double
while zsh uses regulardouble
s. 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.