awkで配列要素を印刷する問題

awkで配列要素を印刷する問題
p=n/1000
printf "%s",arr[p];

値を確認しましたが、何も印刷されませんp
かなりよく出てきました。
また、次の方法で要素を印刷してみました。

printf "%s",arr[7];

これはうまくいきます。

答え1

で述べたようにGNU Awkユーザーガイド8.2数字で配列を添字化する

配列について覚えておくべき重要な点は、配列添字は常に文字列であることです。数値が下付き文字として使用される場合、下付き文字に使用される前に文字列値に変換されます。

その場合はn7432です。デフォルトでは丸めは行われませんn/10007.432だから

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = n/1000; print p, arr[p]}'
7.432 foo

しかし、

$ awk -vn=7432 'BEGIN{arr[7] = "seven"; arr["7.432"] = "foo"; p = int(n/1000); print p, arr[p]}'
7 seven

答え2

補足@steeldriverの素晴らしい答え

7432/1000は整数ではありません。浮動小数点数は、awkC コンパイラdouble型を使用して内部で表現されます。 x86のGNUシステムでは、IEEE 754バイナリ64です。

1/3 を 10 進数で表現できないように (つまり、0.33333 には無数の 3 がある)、7432/1000 も 2 進数で表現できません。この数値awkのおおよその値doubleは2進数であり、これを10進数に戻すと(正確に)7.4320000000000003836930773104541003704071044921875です。

awk整数以外の値を文字列表現に変換すると、バイナリ内部表現の正確な値は完全に保存されません。上記の数字のほとんどが実際にエラーを示すことを考えると、これはあまり役に立ちません。代わりに、次の形式をCONVFMT含むprintf特殊引数を使用して浮動小数点を文字列に変換します。

デフォルト値CONVFMTはyesです%.6g。これは、文字列に変換するときに小数点以下6桁しか保持されないことを意味します。これは何でも変更できますが、浮動小数点指定子(%e、、、 ...)のみ%f%g移植可能であることに注意してください。

これらの数値は、文字列を期待する関数または演算子(たとえばsubstr()、接続...)の引数として使用されると、文字列に変換されます。

@steeldriverが言ったように、その1つは常に文字列である連想配列の中核です。

だからそれはa[7432/1000] = x実際にすることですa[sprintf(CONVFMT, 7432/1000)]。デフォルト値を使用するとにCONVFMTなり、または if に変更するa["0.7432"] = xとになります。CONVFMT%.1ea["7.0e-01"] = x%.25ga["7.4320000000000003837"] = x

したがって、ここで実際には次のように配列のCONVFMT=%.0fキーが整数であることを確認できます。

$ awk -v CONVFMT=%.0f 'BEGIN{a[7432/1000] = 1; print a[7]}'
1

しかし、%.0f最も近い整数に丸めると、%d小数部分も切り捨てられます。 andと一緒に使用できますが、CONVFMT=%d次のように移植することはできません。gawkmawk

$ gawk -v CONVFMT=%d 'BEGIN{a[7564/1000] = 1; print a[7]}'
1
$ gawk -v CONVFMT=%.0f 'BEGIN{a[7564/1000] = 1; print a[8]}'
1

¹以下を使用してprint変換された浮動小数点引数は除外されます。OFMT

関連情報