ヤフー株式会社は、2023年10月1日にLINEヤフー株式会社になりました。LINEヤフー株式会社の新しいブログはこちらです。LINEヤフー Tech Blog

テクノロジー

awkでの数値演算注意

オークション事業部 プラットフォーム技術 後藤です。

私たちのチームはauctionリスト、サーチ、課金などのサービスの運用業務を
行っておりますが、今回は課金の検算などでよく利用するawkでの数値演算につ
いてレポートします。

消費税算出など小数点付きのものを四則演算する場合、awk(表示形式のデフォル
ト書式)を用いて生成する場合、以下ような現象が出ますので注意が必要です。
「7けた以上で科学表記になる場合がある」
「小数点を含めたけた数が7けた以上になると、誤差が出る場合がある」
などです。

以下の理屈が分かっていれば、なにも不思議はないのですが、結構誤差が出るパ
ターンも多いので、利用者の意識が必要なのだなーと思っています。

[awkの説明]
print 文を数値を出力するために使った場合、awkは内部で数値を (その数値を表す)文字列に変換し、
その文字列を出力する。 awkはこの変換動作のためにsprintf関数を使用する。
組込み変数のOFMTは、出力をおこなうときにprintがsprintf を使って数値を文字列に変換するための
書式のデフォルト設定を保持している。
OFMTのデフォルトの値は"%.6g"である。
CONVFMTのデフォルトの値は"%.6g"であり、これは値を最低6文字あるとして変換する。
awkではすべての数値は倍精度の浮動小数点数である。
最近のマシンの大部分では倍精度実数は十進数で16から17けたの精度がある。
Controlling Numeric Output with print抜粋


[sprintfの形式]
"%.6g" 科学表記か浮動小数点表記の、いずれか出力するキャラクタ数が少なくなる方で出力する。
"%.6e" 数値を科学(または指数)形式で出力する。
"%.6f" 浮動小数点表記で小数点以下のけた数表示指定する。


[表記説明]
科学表記は10のべき乗で表す
  echo ""|awk '{ OFMT = "%.6e"} {print 100000000000}'
結果:1.000000e+11
(浮動小数点表記はXXXXX.XXの形で表す)
  echo ""|awk '{ OFMT = "%.6f"} {print 100000000000}'
結果:100000000000.000000

[浮動小数点数型と誤差]
・表示形式による表記違い(計算結果が7けた以上の場合)
OFMTのデフォルトの値は"%.6g"ですので、科学表記か浮動小数点表記いずれかの出力になります。
 表記はキャラクタ数が少なくなる方で出力されます。
 echo "" | awk '{ OFMT = "%.6g"} {print 1815755+0.95  }'
結果:1.81576e+06

・丸め誤差(近い整数に丸められる)
OFMTのデフォルトの値は"%.6g"ですので、小数点を含めたけた数が7けた以上
 になると、誤差が出る場合があります。
 echo "" | awk '{ OFMT = "%.6e"} {print 223359*0.05  }'
結果:11168
(本来「11167.95」からの切り捨てデータとして「11167」を欲してますが、 近い整数に丸められています)

・表示形式による情報落ち(小さな値)
OFMTのデフォルトの値は"%.6g"ですので、6けた以下の情報は失われます。
 echo "" | awk '{ OFMT = "%.6g"} {print 1/3 }'
結果:0.333333
(0.0000003333のデータは失われます)

・丸め誤差(小さな値の情報落ち)
 絶対値が大きな値と小さな値とを加えた場合、小さい方の数値がもつ情報は失われます。
 echo "" | awk '{ OFMT = "%.6g"} {print 77777.7 + 1.23456}' 
結果:77778.9
(0.03456のデータは失われます)


こちらの記事のご感想を聞かせください。

  • 学びがある
  • わかりやすい
  • 新しい視点

ご感想ありがとうございました

このページの先頭へ