我有一个这样的文件:
0.2
0.2
0.2
0.2
0.2
0.2
0.2024
0.2025
0.2027
0.2027
0.2029
0.2059
0.2059
0.2059
0.2059
0.2099
0.2099
0.2099
0.2105
0.2113
0.2113
0.2195
0.2198
0.2206
0.2206
0.2206
0.2989
0.2989
0.2989
0.3
0.3
我想计算一个范围内包含的值的数量,例如:
0.2 18
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 3
0.3 2
如您所见,我使用的间隔为 0.01。我正在用来awk
实现它,但我遇到了一些奇怪的行为:
awk 'BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0} {
for (j=0;j<=1;j+=0.01)
if($1>=j && $1<j+0.01) {
a[j]+=1
}
}
END {for (k=0;k<1.01;k+=0.01) print k,a[k]}' test_OH.txt
结果:
0.19 6
0.2 12
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 5
0.3 0
有人可以帮助我吗?我猜想<
它没有按预期工作,因为它满足 when $1 == j+0.01
.当然,我没有考虑什么。谢谢你!
答案1
awk -v s=0.2 -v e=0.3 -v d=0.01 '
BEGIN { m = 1/d }
{ a[int($1*m)]++ }
END{ e *= m; for(s = int(s*m); s <= e; s++) print s*d, a[s]+0 }
' test_OH.txt
0.2 18
0.21 5
0.22 3
0.23 0
0.24 0
0.25 0
0.26 0
0.27 0
0.28 0
0.29 3
0.3 2
(开始s
)e
(结束)和d
(增量/步长)变量可以根据需要进行调整。
通过重复相加生成一个范围
0.01
几乎是教科书上关于浮点数不能做什么的例子,因为浮点数0.01
不能精确地用基数 2 表示,而且每次相加误差都会累积。扫描每条线的整个范围是低效且毫无意义的。
awk 中的变量不必初始化为
""
or0
。
答案2
试试这个:
awk '
BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0}
{
n = int($1 * 100) / 100
a[n] += 1
}
END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'
或者这个,我觉得不太容易理解:
awk 'BEGIN {for (i=0;i<1.01;i+=0.01) a[i]=0} {
for (j=0;j<=1;j+=0.01)
if(("X" $1 >= "X" j) && ("X" $1 < "X" j+0.01)) {
a[j]+=1
}
}
END {for (k=0;k<1.01;k+=0.01) print k,a[k]}'
至于原版不起作用的原因,请参见上面卡西莫多的评论。
答案3
不确定我是否应该将此作为答案或评论发布,但这里有一个简短的演示,说明了我的机器上这种情况下的不准确性和结果数字:
$ awk 'BEGIN { d = 0.01; printf "%.20f\n", d; for (i = 0; i < 30; i++) a += d; printf "%.20f\n%.20f\n", 0.3, a }'
0.01000000000000000021
0.29999999999999998890
0.30000000000000009992
第一个数字是 0.01 实际存储的数字,它不准确,因为 1/100 包含一个因子 1/5 并且不能用二进制表示。
第二个是 0.3 存储的内容,第三个是 0.01 加上自身 30 次。 (我想,这甚至不一样,0.01 * 30
因为每一步都有中间舍入。)
其他答案都有解决方案,点赞吧。