ちょっとよくわからない現象にでくわしたのでメモ。
整数から微妙にずれた浮動小数点数というのを作ることがありますね。たとえば 1.0/5.0 を5倍するとか。
どうもそれをawk配列引数にすると変なことが起こります。
調べてみましょう。1より微少量大きな数値を作って、配列添字にして参照できるか試してみます。
aryidx.awk
BEGIN {
print CONVFMT
a[1] = 1
a[2] = 2
epsilon = 1
for (i = 0; i <= 60; i++) {
j = 1 + epsilon
epsilon *= 0.5
print "1+2**", -i, "=", j, "<", a[j], ">"
}
}
実行すると、よくわからないのが次の3点:
- 浮動小数点数を文字列変換するときに、CONVFMT 組み込み変数(値 "%.6g")を使うはずなのだが、どうも桁数が違う(実際、CONVFMT 変数を書き換えてみても1行目以外出力が変わらない)
- 配列添字は文字列で、数値を与えた場合には文字列に変換して用いる、とされているのだが、文字列変換結果が "1" なのに配列参照結果が a[1] と同じにならない場合がある
- おそらく、倍精度浮動小数点数として異なるものは、配列添字として別に扱われるようだ(1+2**-53は倍精度で表現できるが、1+2**-54は1と区別できなくなってしまうため)
$ gawk -f aryidx.awk
%.6g
1+2** 0 = 2 < 2 >
1+2** -1 = 1.5 < >
1+2** -2 = 1.25 < >
1+2** -3 = 1.125 < >
1+2** -4 = 1.0625 < >
1+2** -5 = 1.03125 < >
1+2** -6 = 1.01562 < >
1+2** -7 = 1.00781 < >
1+2** -8 = 1.00391 < >
1+2** -9 = 1.00195 < >
1+2** -10 = 1.00098 < >
1+2** -11 = 1.00049 < >
1+2** -12 = 1.00024 < >
1+2** -13 = 1.00012 < >
1+2** -14 = 1.00006 < >
1+2** -15 = 1.00003 < >
1+2** -16 = 1.00002 < >
1+2** -17 = 1.00001 < >
1+2** -18 = 1 < >
1+2** -19 = 1 < >
1+2** -20 = 1 < >
1+2** -21 = 1 < >
1+2** -22 = 1 < >
1+2** -23 = 1 < >
1+2** -24 = 1 < >
1+2** -25 = 1 < >
1+2** -26 = 1 < >
1+2** -27 = 1 < >
1+2** -28 = 1 < >
1+2** -29 = 1 < >
1+2** -30 = 1 < >
1+2** -31 = 1 < >
1+2** -32 = 1 < >
1+2** -33 = 1 < >
1+2** -34 = 1 < >
1+2** -35 = 1 < >
1+2** -36 = 1 < >
1+2** -37 = 1 < >
1+2** -38 = 1 < >
1+2** -39 = 1 < >
1+2** -40 = 1 < >
1+2** -41 = 1 < >
1+2** -42 = 1 < >
1+2** -43 = 1 < >
1+2** -44 = 1 < >
1+2** -45 = 1 < >
1+2** -46 = 1 < >
1+2** -47 = 1 < >
1+2** -48 = 1 < >
1+2** -49 = 1 < >
1+2** -50 = 1 < >
1+2** -51 = 1 < >
1+2** -52 = 1 < >
1+2** -53 = 1 < 1 >
1+2** -54 = 1 < 1 >
1+2** -55 = 1 < 1 >
1+2** -56 = 1 < 1 >
1+2** -57 = 1 < 1 >
1+2** -58 = 1 < 1 >
1+2** -59 = 1 < 1 >
1+2** -60 = 1 < 1 >
$ gawk --version | head -1
GNU Awk 4.1.3, API: 1.1 (GNU MPFR 3.1.4, GNU MP 6.1.0)
オチはありませんよ。