Reputation: 144740
I was trying a very simple printf
test:
printf "%.16f\n" 5.10
On linux I got this output: 5.100000000000000000
which is expected.
But the very same test on OS/X produces this: 5.0999999999999996
Why does printf
produce different output?
EDIT: This is not C code, printf
is also a command-line utility, handy for scripts and tests.
The equivalent C program below produces 5.100000000000000000
:
#include <stdio.h>
int main() {
printf("%.16f\n", 5.10);
return 0;
}
EDIT 2: The plot thickens... to make this more interesting for linux users, if I run this command as nobody
, I get the same behavior as on OS/X:
chqrlie$ printf "%.18f\n" 5.10
5.100000000000000000
chqrlie$ su nobody -c 'printf "%.18f\n" 5.10'
5.099999999999999645
Upvotes: 6
Views: 853
Reputation: 157967
Both the GNU implementation and the MacOS (FreeBSD) implementation of printf
are different programs. Both aim to be compatible with the POSIX standard.
POSIX leaves the representation of floating point numbers open to the implementation of printf. Their argumentation is that all calculation in shell is integer anyway.
The floating-point formatting conversion specifications of printf() are not required because all arithmetic in the shell is integer arithmetic. The awk utility performs floating-point calculations and provides its own printf function. The bc utility can perform arbitrary-precision floating-point arithmetic, but does not provide extensive formatting capabilities. (This printf utility cannot really be used to format bc output; it does not support arbitrary precision.) Implementations are encouraged to support the floating-point conversions as an extension.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html
PS:
5.1
is not a floating point number in bash. bash does not support floating numbers.
5.1
is a string, interpreted by printf
depending on the locale(!)
theymann@theymann-laptop:~/src/sre/inventory-schema$ LANG=en_US.UTF8 printf "%.16f\n" 5.10
5.1000000000000000
theymann@theymann-laptop:~/src/sre/inventory-schema$ LANG=de_DE.UTF8 printf "%.16f\n" 5.10
bash: printf: 5.10: Ungültige Zahl. # << German: Bad Number
0,0000000000000000
Note: In Germany we use , as the decimal separator.
The difference in the output between a normal user and nobody must the shell which is used. some shells, like busybox come with their own implementation of printf
. Btw, I'm extremely surprised that nobody is allowed to execute commands on your system!
Upvotes: 8
Reputation: 36401
This is because floating point types mostly can't represent exact values. For example using an online IEE754 tool you got:
So 5.1
is not exactly representable using this format.
Then printf
(or whatever) is free to format/print any value that it thinks suitable for the user.
Upvotes: 3