次のようなファイルがあります:
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
<
誰か助けてくれませんか?が期待どおりに動作していないのは、 のとき を満たすからだと思います$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 内の変数はまたはに初期化する必要はありません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 が含まれており、これを 2 進数で表すことはできないため、正確ではありません。
2 番目は 0.3 が保存される値で、3 番目は 0.01 を 30 回加算した値です。(各ステップで中間の丸めが行われるため、同じ値ではありません0.01 * 30
。)
他の回答には解決策がありますので、賛成票を投じてください。