整数化
$ awk 'BEGIN {print int(1.5)}' 1
AWKには整数部を表示する関数int()があります。
ところで、AWKには「あって当然」の四捨五入を行う関数がありません。正の数に関して四捨五入は、次のようにすることで計算できます。
$ awk 'BEGIN {a = 1.5; print int(a + 0.5)}' 2
ネット上の記事で、printf文で四捨五入する、という類いの記事を見かけることがあります。これは誤りですので注意してください。printf文には四捨五入のような機能はありません。次の例を見てください。
$ awk 'BEGIN{printf("%.2f\n", 110.115)}' 110.11 $ gawk 'BEGIN{printf("%.2f\n", 110.1151)}' 110.12
printf文にはどのように丸めて表示するかは定められていないため、上記のような変な結果が返っても文句を言えないことになります。
四捨五入などの処理を行うには必ず、その処理を記載するようにしてください。ただし、gawkの最新版では、printf文の丸めをどうするかについて設定できるようになっています。
問題
では、ここで皆さんに問題です。次の結果はどうなるでしょうか。
$ awk 'BEGIN {print int(70.21 * 100)}'
int()関数の引数を計算すると7021なので、7021と思われるかもしれませんが、答えは7020です。
$ awk 'BEGIN {print int(70.21 * 100)}' 7020
詳細な説明は割愛しますが、70.21は2進数では表現できない数値のため、AWKの中では70.2099999999……として格納されています。そのため、7020となってしまうのです。ところが、この70.21という数値だけが特殊というわけではありません。2進数で計算しているプログラム言語においては10進数で小数点を表現できない場合があるため、この数値以外に同様のケースは存在します。十分に注意してください。
また、AWKに限らず、他の言語でも同様な現象が起こりえるので注意しましょう。例えば、Perlでも同様の結果になります。
$ perl -e 'print int(70.21 * 100) . "\n"' 7020
小数での比較演算子を用いる場合には特に、その境界で正しいふるまいをしているかどうかを確認した上で、比較演算を行うようにしましょう。思わぬところに落とし穴があるかもしれません。
どこまで計算できるのか
では AWKはどこまで(何ビットまで)計算できるのでしょうか。次のプログラムで簡単に調べることができます。まずmawk(マイク・ブレナン氏が実装した拡張版AWK)です。
$ mawk 'BEGIN{printf("%d\n", 2 ^ 31 - 1)}' 2147483647 $ mawk 'BEGIN{printf("%d\n", 2 ^ 32 - 1)}' 2147483647
「2 ^ 31 - 1」と「2 ^ 32 - 1」が同じ結果になっていますね。つまり、mawkは31ビットまでの計算ができます。一方、nawk(new AWK)やgawkの場合には、もっと上の桁まで計算できます。
$ nawk 'BEGIN{printf("%d\n", 2 ^ 53 - 1)}' 9007199254740991 $ nawk 'BEGIN{printf("%d\n", 2 ^ 54 - 1)}' 18014398509481984 $ gawk 'BEGIN{printf("%d\n", 2 ^ 53 - 1)}' 9007199254740991 $ gawk 'BEGIN{printf("%d\n", 2 ^ 54 - 1)}' 18014398509481984
なんとなく正しい値を出しているように見えますが、右端の桁に注目してください。2のN乗は必ず偶数になりますから、2のN乗から1を引いた数は、必ず奇数になるはずです。ところが「2 ^ 54 - 1」は偶数になっており、正しく計算できていません。つまり、nawkとgawkは53ビットまで計算できることになります。
さて、数値計算のために準備されているAWKの関数は、このように必要最小限のものです。他の言語のように、過剰に関数が準備されていないため覚えやすい一方、データが膨大になった場合でも適切に処理できるため、Excelの代わりに用いられることもあるでしょう。Excelのように様々な関数が準備されていると、うれしい場合もありますが、組込関数が覚えられず、リファレンスとにらめっこをすることになります。
AWKの実装のため、srand()やatan2()関数、int()関数のように変わった振る舞いをするものもありますが、実際のプログラムでお目にかかることは少ないでしょう。遭遇する機会があれば思い出してください。
なお、gawkはデフォルトでMPFR(Multiple Precision Floating-Point Reliable)による任意精度計算をサポートし、53ビット以上の計算も簡単に行えます。そのため、数値計算でAWKが活躍する場面も増えましたが、こちらについては機会があれば説明したいと思います。
『USP MAGAZINE』は日本で唯一のシェルスクリプト総合誌(毎月25日発売)。最新号 2014 September(Vol.17)の巻頭は「軽量言語(LL)特集」! LLの歴史や各LLの特徴を「FIGHTING TALKS」でお馴染み法林さんがわかりやすく解説。もちろん、FIGHITNG TALKSも引き続き連載中です! さらに、6月26日に開催された各種軽量言語イベントの実行委員長達が集まったTechLION vol.17再録も収録。LLの魅力を詰め込みました。熊野憲辰さんの「未来に活きる!現場で使える!データモデリング」ではデータマネジメントについて解説。モデリングだけではなくデータの品質も重要なのです。他、好評連載中の「ユニケージエンジニアの作法」やAWK処方箋第6回なども掲載です!
► お求めは、Amazon.co.jp、USP研究所のWebサイト、取り扱い書店まで。
USP MAGAZINE 2014 September(Vol.17)
価格:500円+税
仕様:B5版 64ページ オールカラー
発行人:ユニバーサル・シェル・プログラミング研究所