p=n/1000
printf "%s",arr[p];
値を確認しましたが、何も印刷されませんp
。
かなりよく出てきました。
また、次の方法で要素を印刷してみました。
printf "%s",arr[7];
これはうまくいきます。
答え1
で述べたようにGNU Awkユーザーガイド8.2数字で配列を添字化する
配列について覚えておくべき重要な点は、配列添字は常に文字列であることです。数値が下付き文字として使用される場合、下付き文字に使用される前に文字列値に変換されます。
その場合はn
例7432
です。デフォルトでは丸めは行われませんn/1000
。7.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
7432/1000は整数ではありません。浮動小数点数は、awk
C コンパイラ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
%.1e
a["7.0e-01"] = x
%.25g
a["7.4320000000000003837"] = x
したがって、ここで実際には次のように配列のCONVFMT=%.0f
キーが整数であることを確認できます。
$ awk -v CONVFMT=%.0f 'BEGIN{a[7432/1000] = 1; print a[7]}'
1
しかし、%.0f
最も近い整数に丸めると、%d
小数部分も切り捨てられます。 andと一緒に使用できますが、CONVFMT=%d
次のように移植することはできません。gawk
mawk
$ 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