PythonのDecimal型(10進数浮動小数)で小数を比較する

多くのプログラミング言語で数値は2進数で表されます。
整数を表す際には問題無いのですが、小数を表現する際には問題になったりします。
これはPythonも同様です。

この記事で用いるプログラムはPython3(Anaconda 2.1.0)のインタラクティブシェルを利用して実行した結果です。
実行結果は以下の規則に従って記載します。(インタラクティブシェルの貼り付け)

>>> 実行コマンド
出力
>>> print("hoge")
hoge

 

問題点

具体例で示したいと思います。

>>> 0.1*3
0.30000000000000004

a*3は0.3になって欲しいところですが、謎の0.300…004が入っています。
これはプログラミングを勉強したことがある方ならどこかで聞いたことがあると思いますが、2進数では(2^-nの和で表せない)小数を正確に表すことができず、実は微妙にズレた値になっています。この値を計算することによって誤差が発生してしまいます。
この誤差により、0.1 * 3 と 0.3 は違うと判定され期待通りの動作をしてくれません。

>>> if 0.1*3 == 0.3:
...   print("同じだよ")
... else:
...   print("違うよ")
...
違うよ

 

 

Decimal型

そんな時Decimal型が便利です。Decimal型は

「(Decimal は) 人々を念頭にデザインされた浮動小数点モデルを元にしており、必然的に最も重要な指針があります – コンピュータは人々が学校で習った算術と同じように動作する算術を提供しなければならない」 – 10進数演算仕様より。9.4. decimal — 10進固定及び浮動小数点数の算術演算 — Python 3.5.2 ドキュメント

と説明されています。(たぶん英語の原文を訳したもので日本語が怪しい)
ざっくり、有効桁数を考慮した小数型みたいな感じです。

これを利用すると、先程のプログラムは期待通りの動作をしてくれます。

>>> from decimal import Decimal
>>> if Decimal('0.1')*3 == Decimal('0.3'):
...   print("同じだよ")
... else:
...   print("違うよ")
...
同じだよ
>>> print(Decimal('0.1')*3)
0.3

ポイントとしては、

  • decimalをインポートする
  • Decimalの引数文字列で指定する
  • 比較はDecimal型同士で行う

って事くらいですかね。

 

まとめ

個人的にはif文で小数を比較することは少ない気がするのですが、覚えておいたら使えるときがあると思います。

 

Pocket
このエントリーを Google ブックマーク に追加

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

This site uses Akismet to reduce spam. Learn how your comment data is processed.