我有一个包含 40,000 行的文件
head flower_all
0.992957746478873 0.00704225352112677
0.646410833917366 0.353589166082634
0.992957746478873 0.00704225352112677
0.992957746478873 0.00704225352112677
0.992957746478873 0.00704225352112677
0.992957746478873 0.00704225352112677
0.992957746478873 0.00704225352112677
0.992957746478873 0.00704225352112677
0.5 0.5
我只想保留 3 位有效数字。我想要的输出:
0.992 0.007
0.646 0.353
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.5 0.5
我该怎么做?
答案1
和awk
:
awk '{ printf("%.3g %.3g\n", $1, $2) }' file
根据给定的数据,这会产生
0.993 0.00704
0.646 0.354
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.993 0.00704
0.5 0.5
请注意,0.00704 有五位小数,但有三位有效数字。
如果您想要精确三位小数,请使用%.3f
代替%.3g
并得到
0.993 0.007
0.646 0.354
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.993 0.007
0.500 0.500
使用 GNU 可以将上面的两种变体推广到可变数量的列awk
:
awk -v CONVFMT='%.3g' '{ for (i=1; i<=NF; ++i) $i+=0; print }' file
循环$i+=0
强制awk
将每个字段的值重新格式化为浮点数,它将在考虑到的情况下执行此操作CONVFMT
(它或多或少会执行相当于 的操作$i=sprintf(CONVFMT, $i)
)。
如果你想切号码:
awk '{ for (i=1; i<=NF; ++i) $i=sprintf("%.5s", $i); print }' file
这会将数字视为字符串,并在五个字符后将其截断(假设所有数字都小于 10 且大于零),生成
0.992 0.007
0.646 0.353
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.992 0.007
0.5 0.5
对于稍微更一般的数字切割:
awk '{ for (i=1; i<=NF; ++i) if (match($i,".*\\.[0-9]?[0-9]?[0-9]?")) $i=substr($i,RSTART,RLENGTH); print }' file
循环中的操作会在给定正则表达式匹配结束的位置(如果匹配)削减数字。
答案2
您的数据没有超过 1 的数字。我扩展了源文件以包含一些在点前有更多数字的值:
$ cat infile
0.992957746478873 0.00704225352112677
0.646410833917366 0.353589166082634
0.992957746478873 0.00704225352112677
0.5 0.5
16.258137489137 333444.277775666
16.233399999999 333777.277111111
打印函数
一种可能的解决方案是使用 C 兼容的 printf 函数(awk 有一个):
f 格式(小数点后 3 位(四舍五入))
精确到小数点后 3 位(四舍五入):
$ awk '{ printf("%11.3f %11.3f\n", $1,$2) }' infile
0.993 0.007
0.646 0.354
0.993 0.007
0.500 0.500
16.258 333444.278
16.233 333777.277
请注意,0.992957746478873
四舍五入为0.993
。
g 格式(有效(四舍五入))
3 位(有效)数字的精确计数:
$ awk '{ printf("%9.3g %9.3g\n", $1,$2) }' infile
0.993 0.00704
0.646 0.354
0.993 0.00704
0.5 0.5
16.3 3.33e+05
16.2 3.34e+05
请注意第四位数字的四舍五入(例如 3.34e+05)
字符串(未舍入)
小数点后正好 3 位(不四舍五入)。
使用 GNU awk:
$ gawk '{for(i=1;i<=NF;i++){
printf( "%12s ",gensub(/([0-9]+\.[0-9]{0,3}).*/, "\\1", "g", $i))};print""}
' infile
0.992 0.007
0.646 0.353
0.992 0.007
0.5 0.5
16.258 333444.277
16.233 333777.277
使用 sed (可能更快):
$ sed -E 's/([0-9]+\.[0-9]{1,3})[^ ]*/\1/g' infile
0.992 0.007
0.646 0.353
0.992 0.007
0.5 0.5
16.258 333444.277
16.233 333777.277