常规关系运算符 '

常规关系运算符 '

我有一个这样的文件:

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

(开始se(结束)和d(增量/步长)变量可以根据需要进行调整。


  1. 通过重复相加生成一个范围0.01几乎是教科书上关于浮点数不能做什么的例子,因为浮点数0.01不能精确地用基数 2 表示,而且每次相加误差都会累积。

  2. 扫描每条线的整个范围是低效且毫无意义的。

  3. awk 中的变量不必初始化为""or 0

答案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因为每一步都有中间舍入。)

其他答案都有解决方案,点赞吧。

相关内容