I've read some answers on this site and found the printf
rounding desirable.
However when I used it in practice, a subtle bug led me to the following behavior:
$ echo 197.5 | xargs printf '%.0f'
198
$ echo 196.5 | xargs printf '%.0f'
196
$ echo 195.5 | xargs printf '%.0f'
196
Notice that rounding 196.5
becomes 196
.
I know this can be some subtle floating point bug (but this is not a very large number, huh?), so can someone throw some light upon this?
An workaround for this is also greatly welcomed (because I'm trying to put this to work now).
Best Answer
It is as expected, it is "round to even", or "Banker's rounding".
A related site answer explain it.
The issue that such rule is trying to solve is that (for numbers with one decimal),
That's 4 down and 4 up.
To keep the rounding in balance, we need to round the x.5
That is done by the rule: « Round to nearest 'even number' ».
In code:
sh
LC_NUMERIC=C printf '%.0f ' "$value"
awk
echo "$value" | awk 'printf( "%s", $1)'
Options:
In total, there are four possible ways to round a number:
Up
If you do need "round up (toward
+infinite
)", then you can use awk:awk
echo "$value" | awk '{ printf("%d", $1 + 0.5) }'
bc
echo "scale=0; ($value+0.5)/1" | bc
Down
If you do need "round down (Toward
-infinite
)", then you can use:awk
echo "$value" | awk '{ printf("%d", $1 - 0.5) }'
bc
echo "scale=0; ($value-0.5)/1" | bc
Trim decimals.
To remove the decimals (anything after the dot).
We could also directly use the shell (works on most shells - is POSIX):
shell
echo "${value%%.*}"
awk
echo "$value"| awk '{printf ("%d",$0)}'
bc
echo "scale=0; ($value)/1" | bc