我有下面的test.txt文件-
var,value
a,1.1234
b,1.7896749
c,2.4982
d,1.2976232
当我使用以下命令时-
awk -F ',' '{SUM+=$2}END{print SUM}' test.txt
它打印6.7089
但是,所有小数位的结果都是6.7088981如何编写命令,以便它在结果中打印所有十进制位,不仅在这种特定情况下,而且在一般情况下。例如,如果结果有10位小数,它应该打印所有的10位小数点吗?如果结果只有5位小数,它应该只打印5位小数。我使用的操作系统是服务器7.7
发布于 2020-02-20 15:58:44
打印时,使用OFMT
特殊变量将非整数数字转换为十进制字符串表示,该变量包含printf
格式规范(默认情况下为%.6g
)。您可以将其更改为%.17g
,以获得IEEE754双精度二进制浮点数的最大精度(大多数系统上大多数awk
实现都在内部使用)。在其他情况下使用另一个变量(CONVFMT
),即浮点数被隐式转换为字符串(例如,当您将一个数字与其他东西连接时)。
你不会获得更高的精度,这些双打,没有任何意义超过17。已经有17,你很可能会看到一些文物。如果你不需要那么高的精度,那么15位重要的数字可能会更好。
$ awk -v OFMT=%.17g -F ',' '{SUM+=$2};END{print SUM}' < file
6.7088981000000008
$ awk -v OFMT=%.15g -F ',' '{SUM+=$2};END{print SUM}' < file
6.7088981
虽然OFMT
影响所有打印的浮点数,但您也可以直接使用printf
打印所需精度的数字。
$ awk -F ',' '{SUM+=$2};END{printf "%.15g\n", SUM}' < file
6.7088981
awk
的GNU实现,因为4.1.0版本也可以编译任意精确算法支持(参见info gawk 'Arbitrary Precision Arithmetic'
)。如果你的系统是这样的话,你也可以这样做:
gawk -M -v PREC=256 -v OFMT=%.60g -F ',' '{SUM+=$2};END{print SUM}' < file
示例:
$ printf 'x,%s\n' 1 1000000000000000000000000000000000.00000000001 |
> gawk -v OFMT=%.15g -F ',' '{SUM+=$2};END{print SUM}'
999999999999999945575230987042816
$ printf 'x,%s\n' 1 1000000000000000000000000000000000.00000000001 |
> gawk -M -v PREC=256 -v OFMT=%.60g -F ',' '{SUM+=$2};END{print SUM}'
1000000000000000000000000000000001.00000000001
这里的另一种方法可以是使用bc
(假设这些数字总是这样表示的(例如,0.001
,而不是1e-3
)):
.之后的数字数将是任何输入记录中的最大数字。
发布于 2020-02-20 15:59:12
发布于 2020-02-20 16:41:22
正如已经讨论过的,浮点算法是试图获得直观答案时的问题,但是如果您知道您的输入只能达到,例如,3位数之前的“。例如,9之后,您可以使用字符串操作将数字转换为小数,然后对其进行求和以避免浮点运算问题,然后在打印之前再次将结果转换回FP,例如:
$ cat tst.awk
BEGIN {
FS = ","
bef = 3
aft = 9
}
NR>1 {
split($2,f,".")
val = sprintf("%*s%-*s",bef,f[1],aft,f[2])
gsub(/ /,0,val)
sum += val
}
END {
sub(".{"aft"}$",".&",sum)
sub(/0+$/,"",sum)
print sum
}
$ awk -f tst.awk file
6.7088981
如果3和/或9不足以满足您的需要,请选择其他数字或进行2次传递,在第一次通过时计算出每个数字的最大值,例如:
$ cat tst.awk
BEGIN { FS = "," }
FNR==1 { next }
{ split($2,f,".") }
NR==FNR {
bef = (length(f[1]) > bef ? length(f[1]) : bef)
aft = (length(f[2]) > aft ? length(f[2]) : aft)
next
}
{
val = sprintf("%*s%-*s",bef,f[1],aft,f[2])
gsub(/ /,0,val)
sum += val
}
END {
sub(".{"aft"}$",".&",sum)
sub(/0+$/,"",sum)
print sum
}
$ awk -f tst.awk file file
6.7088981
https://unix.stackexchange.com/questions/568748
复制相似问题