一般関係演算子 '<' が awk で期待どおりに動作しません。

一般関係演算子 '<' が awk で期待どおりに動作しません。

次のファイルがあります。

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

(スタートse(終了)およびd(増分/ステップ)変数は必要に応じて調整できます。


  1. 繰り返し加算で範囲を生成することは、0.01浮動小数点数ができないことを示すほとんどの教科書の例です。なぜなら、浮動小数点数は0.012進法で正確に表現できず、加算するたびに誤差が累積されるからです。

  2. 各ラインの全範囲をスキャンすることは非効率的で意味がない。

  3. ""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]}'

オリジナルが機能しない理由については、上記のQuasimodoの説明を参照してください。

答え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すべての段階で中間丸めがあるため、同じではないようです。)

他の答えには解決策があります。いいねを押してください。

関連情報