awk変数OFMTに指数形式を指定しても整数表示になる場合がある

awk の組み込み変数 OFMT は、print で実数を出力する際のフォーマット(Output FORmat)。 デフォルトは "%.6g" 。

但し、ある特定のケースにおいて、OFMTで指定した形式で出力されないことがある。
OFMTに指数形式を指定して整数値をprintした時だ。

1$ awk 'BEGIN { OFMT = "%.2e"; print 10.1 }'
21.01e+01
3$ awk 'BEGIN { OFMT = "%.2e"; print 10.0 }'
410

上の二番目の実行結果は 1.00e+01 とはならず、 OFMT が効いていない。

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html
上記リンク先の awk の説明に、次のような記述がある。

A numeric value that is exactly equal to the value of an integer (see Concepts Derived from the ISO C Standard) shall be converted to a string by the equivalent of a call to the sprintf function (see String Functions) with the string "%d" as the fmt argument and the numeric value being converted as the first and only expr argument.

◆ 意訳
整数の値と正確に等価な数値は、sprintf(fmt, expr) 関数を fmt="%d", expr=変換対象の数値, として呼び出すのと同じ方法で、文字列に変換される。

つまり、たとえ浮動小数点数であったとしても、実質的に整数と等しければ整数として扱われる・・・ということと思われる。
そして整数に対してOFMTは効かないようだ。

一方、 OFMT を使わず printf の中で指数形式を指定すると、指数形式が効いて出力される。

1$ awk 'BEGIN { printf("%.2e\n", 10.0) }'
21.00e+01

もう一つ気に留めておくべきことがある。
awk で大きい桁数の浮動小数点値を扱うと、小数点以下が 0 に自動変換される。

1$ awk 'BEGIN { printf("%.3f\n", 4503599627370495.749) }'
24503599627370495.500
3$ awk 'BEGIN { OFMT = "%.16e"; print 4503599627370495.749 }'
44.5035996273704955e+15
5$ awk 'BEGIN { printf("%.3f\n", 4503599627370495.750) }'
64503599627370496.000
7$ awk 'BEGIN { OFMT = "%.16e"; print 4503599627370495.750 }'
84503599627370496

3行目のコマンド実行では指数形式で出力されているが、7行目のコマンド実行では 4503599627370495.750 は 4503599627370496.000 となり(5〜6行目参照)、 整数と正確に等価なので整数として扱われる。 よって OFMT が効かず整数形式で出力されている。 この数値付近に awk で扱う浮動小数点値の精度の限界があるのかもしれない。

関連ページ