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

chq*_*lie 6 c linux macos printf sh

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

printf "%.16f\n" 5.10
Run Code Online (Sandbox Code Playgroud)

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

但是在OS / X上进行的完全相同的测试会产生以下结果: 5.0999999999999996

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

编辑:这不是C代码,printf还是命令行实用程序,非常适合脚本和测试。

下面的等效C程序产生5.100000000000000000

printf "%.16f\n" 5.10
Run Code Online (Sandbox Code Playgroud)

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

chqrlie$ printf "%.18f\n" 5.10
5.100000000000000000
chqrlie$ su nobody -c 'printf "%.18f\n" 5.10'
5.099999999999999645
Run Code Online (Sandbox Code Playgroud)

hek*_*mgl 8

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

POSIX使浮点数的表示形式对printf的实现开放。他们的论点是壳中的所有计算无论如何都是整数。

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

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


PS:

5.1
Run Code Online (Sandbox Code Playgroud)

不是在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
Run Code Online (Sandbox Code Playgroud)

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


普通用户和没有人必须使用的外壳之间的输出差异。有些shell,例如busybox都有自己的实现printf。顺便说一句,我非常惊讶没有人被允许在您的系统上执行命令!


Jea*_*nès 3

这是因为浮点类型大多不能表示精确的值。例如,使用在线 IEE754 工具,您可以获得:

在此输入图像描述

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

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

  • @chqrlie 这是不正确的。从字符串到浮点数的正确转换是明确定义的。从另一个方向来看,则绝对不是。例如,Python 2.6 和 Python 2.7 的转换行为有所不同。 (2认同)