taf*_*it3 20 bash awk bc floating-point dc
我想用 bash 中的两个有效数字打印浮点数(可能使用常用工具,如 awk、bc、dc、perl 等)。
例子:
在这两种情况下,有效数字都是 7 和 6。我已经阅读了一些类似问题的答案,例如:
但答案的重点是限制小数位数(例如bccommand withscale=2或printfcommand with %.2f)而不是有效数字。
有没有一种简单的方法可以用正好 2 个有效数字来格式化数字,还是我必须编写自己的函数?
Tob*_*ght 14
对第一个链接问题的回答在结尾处几乎是一次性的:
另请参阅
%g四舍五入到指定数量的有效数字。
所以你可以简单地写
printf "%.2g" "$n"
Run Code Online (Sandbox Code Playgroud)
(但请参阅下面关于小数点分隔符和语言环境的部分,并注意非 Bashprintf不需要支持%f和%g)。
例子:
$ printf "%.2g\n" 76543 0.0076543
7.7e+04
0.0077
Run Code Online (Sandbox Code Playgroud)
当然,您现在拥有尾数指数表示而不是纯十进制,因此您需要转换回来:
$ printf "%0.f\n" 7.7e+06
7700000
$ printf "%0.7f\n" 7.7e-06
0.0000077
Run Code Online (Sandbox Code Playgroud)
将所有这些放在一起,并将其包装在一个函数中:
# Function round(precision, number)
round() {
n=$(printf "%.${1}g" "$2")
if [ "$n" != "${n#*e}" ]
then
f="${n##*e-}"
test "$n" = "$f" && f= || f=$(( ${f#0}+$1-1 ))
printf "%0.${f}f" "$n"
else
printf "%s" "$n"
fi
}
Run Code Online (Sandbox Code Playgroud)
(注意 - 这个函数是用可移植的(POSIX)shell 编写的,但假设它printf处理浮点转换。Bash 有一个内置的printf,所以你在这里没问题,GNU 实现也可以工作,所以大多数 GNU /Linux 系统可以安全地使用 Dash)。
radix=$(printf %.1f 0)
for i in $(seq 12 | sed -e 's/.*/dc -e "12k 1.234 10 & 6 -^*p"/e' -e "y/_._/$radix/")
do
echo $i "->" $(round 2 $i)
done
Run Code Online (Sandbox Code Playgroud)
.000012340000 -> 0.000012
.000123400000 -> 0.00012
.001234000000 -> 0.0012
.012340000000 -> 0.012
.123400000000 -> 0.12
1.234 -> 1.2
12.340 -> 12
123.400 -> 120
1234.000 -> 1200
12340.000 -> 12000
123400.000 -> 120000
1234000.000 -> 1200000
Run Code Online (Sandbox Code Playgroud)
上面的所有工作都假设基数字符(也称为小数分隔符)是.,就像在大多数英语语言环境中一样。其他语言环境,改为使用,并且某些 shell 具有printf尊重语言环境的内置程序。在这些 shell 中,您可能需要设置LC_NUMERIC=C强制使用.as 基数字符,或写入/usr/bin/printf以阻止使用内置版本。由于(至少某些版本)似乎总是使用 解析参数.,但使用当前语言环境设置打印,后者变得复杂。