高精度な小数計算(decimal.Decimal)|Python
Python の float は 2 進浮動小数点数であり、0.1 のような 10 進小数を正確に表現できない。金融計算や会計処理など、10 進数での正確な計算が必要な場面では decimal.Decimal を使う。
Decimal の基本
Decimal は 10 進数を正確に表現できる。
from decimal import Decimal
# float の場合
print(0.1 + 0.1 + 0.1) # 0.30000000000000004
# Decimal の場合
a = Decimal('0.1')
print(a + a + a) # 0.3Decimal は文字列から作成するのが基本だ。Decimal(0.1) のように浮動小数点数から作ると、元の誤差がそのまま持ち込まれる。
from decimal import Decimal
# 文字列から(正確)
Decimal('0.1') # Decimal('0.1')
# float から(誤差を含む)
Decimal(0.1) # Decimal('0.1000000000000000055511151231257827021181583404541015625')四則演算
Decimal 同士の演算は Decimal を返す。
from decimal import Decimal
price = Decimal('1980')
tax_rate = Decimal('0.10')
tax = price * tax_rate
print(tax) # 198.00
print(type(tax)) # <class 'decimal.Decimal'>float と Decimal を直接演算することはできない。型を揃える必要がある。
from decimal import Decimal
a = Decimal('1.5')
b = 2.0
# a + b # TypeError: unsupported operand type(s)
a + Decimal(str(b)) # Decimal('3.5')精度の設定
getcontext() で演算の精度(有効桁数)を設定できる。デフォルトは 28 桁。
from decimal import Decimal, getcontext
getcontext().prec = 50 # 50 桁に設定
result = Decimal(1) / Decimal(7)
print(result)
# 0.14285714285714285714285714285714285714285714285714精度を上げると計算は遅くなるが、必要な桁数を確保できる。
丸めモード
Decimal は丸めの方法を細かく制御できる。金融計算では「銀行丸め(ROUND_HALF_EVEN)」がよく使われる。
from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN
value = Decimal('2.5')
# 四捨五入(一般的な方法)
print(value.quantize(Decimal('1'), rounding=ROUND_HALF_UP)) # 3
# 銀行丸め(最近接偶数への丸め)
print(value.quantize(Decimal('1'), rounding=ROUND_HALF_EVEN)) # 2quantize メソッドで小数点以下の桁数と丸めモードを指定する。
一般的な四捨五入。0.5 は切り上げる。
銀行丸め。0.5 のとき最近接の偶数に丸める。統計的な偏りが少ない。
消費税計算の例
実際の金額計算では、端数処理のタイミングと方法が重要になる。
from decimal import Decimal, ROUND_DOWN
def calc_tax(price, tax_rate=Decimal('0.10')):
"""税込価格を計算(税額は切り捨て)"""
tax = (price * tax_rate).quantize(Decimal('1'), rounding=ROUND_DOWN)
return price + tax
items = [Decimal('198'), Decimal('350'), Decimal('1280')]
for price in items:
total = calc_tax(price)
print(f'{price}円 → {total}円(税込)')消費税の端数処理は法的に決まっていないが、多くの場合は切り捨てが採用される。
float との比較
高速で、科学計算や機械学習に適している。2 進数ベースのため 10 進小数に誤差が出る。
10 進数を正確に扱える。金融・会計向き。速度は float より遅い。
使いどころ
Decimal は以下のような場面で活躍する。
一方、科学計算や機械学習など、大量の数値を高速に処理する必要がある場面では float や NumPy を使う方が適切だ。計算の性質に応じて使い分けることが重要である。



