LoginSignup
19
14

More than 3 years have passed since last update.

Pythonで小数を取り扱う話

Posted at

はじめに

Pythonで、というかコンピュータは小数の扱いが苦手です。
というのもコンピュータは2進数を基準に計算しており、小数を取り扱うのが難しいからです。

多くの場合、コンピュータは小数を扱うとき、その値の近似値を表します。

そのため、次のような計算を行うと、正確な数を計算することができません。

A = 0.33
B = 10.0
print("ans: " + str(A * B))

# ans: 3.3000000000000003

これはつまり、次のような事に注意が必要という事です。

A = 0.33
B = 10.0

if(A * B == 3.3):
    print("一致")
else:
    print("不一致")

# 不一致

というわけでpythonで小数を取り扱うようなライブラリを調べてみました。

decimal

decimalはpythonの標準ライブラリです。
10進数の浮動小数点のための計算を行うために設計されています。

この型を使用すると、人間の感覚に近い計算が行えます。

Doc: https://docs.python.org/ja/3/library/decimal.html

from decimal import *

x = Decimal("0.33")
x10 = x * 10

print("ans: " + str(x10))
print("type: " + str(type(x10)))

# ans: 3.30
# type: <class 'decimal.Decimal'> 

Decimal型の変数はintとの計算では明示的にキャストする必要はありません。

x2 = x + 1
print(x2)

# 1.33

だたしfloat型は明示的にキャストをする必要があります。

x2 = x + 0.003
print(x2)

# TypeError: unsupported operand type(s) for +: 'decimal.Decimal' and 'float'

x2 = x + Decimal(0.003)
print(x2)

# 0.3330000000000000000624500451

あれ?

float型からDecimal型へのキャストは注意が必要

float型からDecimal型にキャストすると、うまく動作しないようです。

float型は小数の近似値をDecimal型に渡すので、その近似値を正確にDecimal型が読んでしまため、このような処理になったものと思われます。
なので、この場合はstr型を経由して、Decimal型にキャストすると良いでしょう。

print(Decimal(0.003))
# 0.003000000000000000062450045135165055398829281330108642578125

print(Decimal(str(0.003)))
# 0.003

終わりに

冒頭で失敗していた比較の演算は次のようになります。

A = Decimal(str(0.33))
B = Decimal(str(10.0))

if(float(A * B) == 3.3):
    print("一致")
else:
    print("不一致")

# 一致
19
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
14