为什么我在linux和OS / X上获得不同的输出

问题描述 投票:6回答:2

我正在尝试一个非常简单的printf测试:

printf "%.16f\n" 5.10

在linux上我得到了这个输出:5.100000000000000000,这是预期的。

但是OS / X上的测试产生了同样的结果:5.0999999999999996

为什么printf会产生不同的输出?

编辑:这不是C代码,printf也是一个命令行实用程序,方便脚本和测试。

下面的等效C程序产生5.100000000000000000

#include <stdio.h>

int main() {
    printf("%.16f\n", 5.10);
    return 0;
}

编辑2:情节变厚......使linux用户更有趣,如果我以nobody运行此命令,我会得到与OS / X相同的行为:

chqrlie$ printf "%.18f\n" 5.10
5.100000000000000000
chqrlie$ su nobody -c 'printf "%.18f\n" 5.10'
5.099999999999999645
c linux macos printf sh
2个回答
8
投票

GNU实现和printf的MacOS(FreeBSD)实现都是不同的程序。两者都旨在与POSIX标准兼容。

POSIX将浮点数的表示留给printf的实现。他们的论证是shell中的所有计算都是整数。

不需要printf()的浮点格式转换规范,因为shell中的所有算术都是整数运算。 awk实用程序执行浮点计算并提供自己的printf函数。 bc实用程序可以执行任意精度的浮点运算,但不提供广泛的格式化功能。 (此printf实用程序实际上不能用于格式化bc输出;它不支持任意精度。)鼓励实现支持浮点转换作为扩展。

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/printf.html


PS:

5.1

不是bash中的浮点数。 bash不支持浮点数。

5.1是一个字符串,由printf解释,具体取决于区域设置(!)

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

注意:在德国,我们使用小数分隔符。


普通用户和无人之间的输出差异必须是使用的shell。一些shell,像busybox一样自带printf。顺便说一下,我很惊讶没有人被允许在你的系统上执行命令!


3
投票

这是因为浮点类型大多数不能代表精确值。例如,您使用在线IEE754工具:

enter image description here

所以5.1使用这种格式并不完全可以表示。

然后printf(或其他)可以自由格式化/打印它认为适合用户的任何值。