首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >求和十进制值时需要在awk求和中的全小数

求和十进制值时需要在awk求和中的全小数
EN

Unix & Linux用户
提问于 2020-02-20 15:45:06
回答 3查看 4.6K关注 0票数 2

我有下面的test.txt文件-

代码语言:javascript
运行
复制
var,value
a,1.1234
b,1.7896749
c,2.4982
d,1.2976232

当我使用以下命令时-

代码语言:javascript
运行
复制
awk -F ',' '{SUM+=$2}END{print SUM}' test.txt

它打印6.7089

但是,所有小数位的结果都是6.7088981如何编写命令,以便它在结果中打印所有十进制位,不仅在这种特定情况下,而且在一般情况下。例如,如果结果有10位小数,它应该打印所有的10位小数点吗?如果结果只有5位小数,它应该只打印5位小数。我使用的操作系统是服务器7.7

EN

回答 3

Unix & Linux用户

回答已采纳

发布于 2020-02-20 15:58:44

打印时,使用OFMT特殊变量将非整数数字转换为十进制字符串表示,该变量包含printf格式规范(默认情况下为%.6g)。您可以将其更改为%.17g,以获得IEEE754双精度二进制浮点数的最大精度(大多数系统上大多数awk实现都在内部使用)。在其他情况下使用另一个变量(CONVFMT),即浮点数被隐式转换为字符串(例如,当您将一个数字与其他东西连接时)。

你不会获得更高的精度,这些双打,没有任何意义超过17。已经有17,你很可能会看到一些文物。如果你不需要那么高的精度,那么15位重要的数字可能会更好。

代码语言:javascript
运行
复制
$ 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打印所需精度的数字。

代码语言:javascript
运行
复制
$ awk  -F ',' '{SUM+=$2};END{printf "%.15g\n", SUM}' < file
6.7088981

awk的GNU实现,因为4.1.0版本也可以编译任意精确算法支持(参见info gawk 'Arbitrary Precision Arithmetic')。如果你的系统是这样的话,你也可以这样做:

代码语言:javascript
运行
复制
gawk -M -v PREC=256 -v OFMT=%.60g -F ',' '{SUM+=$2};END{print SUM}' < file

示例:

代码语言:javascript
运行
复制
$ 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 )):

代码语言:javascript
运行
复制

.之后的数字数将是任何输入记录中的最大数字。

票数 4
EN

Unix & Linux用户

发布于 2020-02-20 15:59:12

GNU数据使用其默认输出设置以所需的精度显示数字:

代码语言:javascript
运行
复制
$ datamash --header-in -t, sum 2 < test.txt
6.7088981

或者使用更精确的不同OFMT的awk:

代码语言:javascript
运行
复制
$ awk -F, -v OFMT='%.10g' '{sum += $2} END { print sum }' test.txt
6.7088981

但请看浮点数学坏了吗?。当浮点数显示在基数10中时,小数点后的数字数并不总是与(大多数)计算机使用的IEEE754 2表示形式相对应。

票数 2
EN

Unix & Linux用户

发布于 2020-02-20 16:41:22

正如已经讨论过的,浮点算法是试图获得直观答案时的问题,但是如果您知道您的输入只能达到,例如,3位数之前的“。例如,9之后,您可以使用字符串操作将数字转换为小数,然后对其进行求和以避免浮点运算问题,然后在打印之前再次将结果转换回FP,例如:

代码语言:javascript
运行
复制
$ 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次传递,在第一次通过时计算出每个数字的最大值,例如:

代码语言:javascript
运行
复制
$ 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
票数 1
EN
页面原文内容由Unix & Linux提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://unix.stackexchange.com/questions/568748

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档