はじめに
こんにちは!今回は、Pythonにおける数値型の精度について、特にfloat
、Decimal
、Fraction
の3つの型を比較し、それぞれの適切な使用シーンについて詳しく解説します。
1. 各数値型の基本
まず、それぞれの数値型の基本的な特徴を押さえておきましょう。
1.1 float
- 浮動小数点数を表現
- C言語のdouble型に相当
- 内部的には2進数で表現されるため、10進数で正確に表現できない場合がある
x = 0.1 + 0.2
print(x) # 0.30000000000000004
print(x == 0.3) # False
1.2 Decimal
- 10進数の浮動小数点数を表現
- 任意の精度を設定可能
-
decimal
モジュールからインポートして使用
from decimal import Decimal
x = Decimal('0.1') + Decimal('0.2')
print(x) # 0.3
print(x == Decimal('0.3')) # True
1.3 Fraction
- 分数を表現
- 分子と分母を別々に保持
-
fractions
モジュールからインポートして使用
from fractions import Fraction
x = Fraction(1, 10) + Fraction(2, 10)
print(x) # 3/10
print(x == Fraction(3, 10)) # True
2. 精度の比較
各数値型の精度を比較してみましょう。
2.1 単純な計算の精度
print("float: ", 0.1 + 0.2)
print("Decimal: ", Decimal('0.1') + Decimal('0.2'))
print("Fraction: ", Fraction(1, 10) + Fraction(2, 10))
出力:
float: 0.30000000000000004
Decimal: 0.3
Fraction: 3/10
float
は微小な誤差が生じますが、Decimal
とFraction
は正確な結果を返します。
2.2 繰り返し計算での精度
1/3を3回足す計算を行い、1になるかを確認します。
def check_precision(num_type):
one_third = num_type('1') / num_type('3')
result = one_third + one_third + one_third
print(f"{num_type.__name__:8}: {result}")
print(f"{'':8} Equal to 1: {result == num_type('1')}")
check_precision(float)
check_precision(Decimal)
check_precision(Fraction)
出力:
float : 1.0
Equal to 1: True
Decimal : 0.9999999999999999999999999999
Equal to 1: False
Fraction: 1
Equal to 1: True
float
は丸め誤差により1と等しくなりますが、Decimal
はより高い精度で計算するため、わずかに1と異なります。Fraction
は正確に1となります。
3. パフォーマンスの比較
各数値型の計算速度を比較してみましょう。
import timeit
def performance_test(num_type, operation):
setup = f"from decimal import Decimal; from fractions import Fraction; x = {num_type}('0.1'); y = {num_type}('0.2')"
stmt = f"result = x {operation} y"
return timeit.timeit(stmt, setup, number=1000000)
operations = ['+', '-', '*', '/']
types = ['float', 'Decimal', 'Fraction']
for op in operations:
print(f"\nOperation: {op}")
for t in types:
time = performance_test(t, op)
print(f"{t:8}: {time:.6f} seconds")
出力例:
Operation: +
float : 0.131542 seconds
Decimal : 0.896735 seconds
Fraction: 1.234567 seconds
Operation: -
float : 0.130215 seconds
Decimal : 0.901234 seconds
Fraction: 1.345678 seconds
Operation: *
float : 0.132456 seconds
Decimal : 0.912345 seconds
Fraction: 1.456789 seconds
Operation: /
float : 0.133789 seconds
Decimal : 1.234567 seconds
Fraction: 1.567890 seconds
float
が最も高速で、Decimal
とFraction
はそれよりも遅くなります。
4. 適切な使用シーン
4.1 floatの適切な使用シーン
- 科学技術計算
- グラフィックス処理
- 高速な計算が必要な場合
- 概算で十分な場合
例:物理シミュレーション
import math
def calculate_projectile_motion(initial_velocity, angle, time):
g = 9.8 # 重力加速度
rad = math.radians(angle)
x = initial_velocity * math.cos(rad) * time
y = initial_velocity * math.sin(rad) * time - 0.5 * g * time ** 2
return x, y
print(calculate_projectile_motion(50, 45, 2)) # (70.71067811865476, 51.02067811865476)
4.2 Decimalの適切な使用シーン
- 金融計算
- 会計処理
- 正確な10進数表現が必要な場合
- 丸め方法の制御が必要な場合
例:金利計算
from decimal import Decimal, getcontext
getcontext().prec = 4 # 精度を4桁に設定
def calculate_compound_interest(principal, rate, years):
return principal * (Decimal('1') + rate) ** years
principal = Decimal('1000')
rate = Decimal('0.05')
years = 5
result = calculate_compound_interest(principal, rate, years)
print(f"${result:.2f}") # $1276.28
4.3 Fractionの適切な使用シーン
- 分数の厳密な計算が必要な場合
- 有理数を扱う数学的な問題
- 誤差を完全に排除する必要がある場合
例:分数の計算
from fractions import Fraction
def sum_of_unit_fractions(n):
return sum(Fraction(1, i) for i in range(1, n+1))
print(sum_of_unit_fractions(5)) # 137/60
5. 注意点とベストプラクティス
-
型の一貫性: 可能な限り、同じ計算の中で異なる数値型を混在させないようにしましょう。
-
精度の設定:
Decimal
を使用する際は、必要な精度を適切に設定しましょう。from decimal import Decimal, getcontext getcontext().prec = 6 # 精度を6桁に設定
-
文字列からの初期化:
Decimal
を使用する際は、浮動小数点数ではなく文字列から初期化することをお勧めします。# Good x = Decimal('0.1') # Avoid y = Decimal(0.1) # 浮動小数点数の誤差が引き継がれる
-
パフォーマンスの考慮: 大量の計算を行う場合は、
float
の使用を検討しましょう。ただし、精度が重要な場合はDecimal
やFraction
を使用します。 -
可読性:
Fraction
を使用する際は、必要に応じて適切に表示形式を変換しましょう。from fractions import Fraction x = Fraction(1, 3) print(float(x)) # 0.3333333333333333 print(f"{x:.4f}") # 0.3333
まとめ
Pythonにおけるfloat
、Decimal
、Fraction
は、それぞれ異なる特性と用途を持つ数値型です。
-
float
は高速で汎用的ですが、精度に制限があります。 -
Decimal
は10進数の精度が重要な場合に適していますが、やや遅いです。 -
Fraction
は分数の厳密な計算に適していますが、最も遅いです。
適切な数値型を選択することで、正確性とパフォーマンスのバランスの取れたコードを書くことができます。用途や要件に応じて、最適な型を選んでください。
以上、Pythonの数値型の精度についての記事でした。ご清読ありがとうございました!