メモ_Pythonでの小数点計算の計算速度を、float、decimal、fractionそれぞれで比較してみた。

Pythonに限った話ではありませんが、コンピューターで小数点の計算をさせると誤差が生じるため、期待通りの計算結果が得られないことがあります。

 

例えば、0.1+0.2 は 0.3 ではなく、0.30000000000000004 となります。

10進数小数を正確に計算するためにdecimalモジュールがよく使われますが、割り算で罠があり、1÷60×60 は 60 ではなく、59.99999999999999999999999999 となります。
(1÷60が割り切れず、丸め誤差が生じる)



そこで、10進数小数を分数として扱える便利なものとして、fractionsモジュールがあります。fractionsモジュールを使うと上記の「0.1+0.2」や「1÷60×60」が正しく計算できます。

 

しかし、fractionモジュールで計算は処理が重いです。

float、decimal、fractionそれぞれで同じ計算をした結果を比較してみました。

 

計算内容:

小数点以下の数字をランダムに、1000個を生成して、それらを1000回づつ加減乗除した計算を行い、最後に時間を計測して表示します。

 

コード:

通常のfloatでの処理


import random
import time

random_numbers = [random.random() for _ in range(1000)]
operations = ['+', '-', '*', '/']
total_operations = 1000

start_time = time.time()

for _ in range(total_operations):
    result = random_numbers[0]
    for i in range(1, len(random_numbers)):
        operation = random.choice(operations)
        num = random_numbers[i]
        if operation == '+':
            result += num
        elif operation == '-':
            result -= num
        elif operation == '*':
            result *= num
        elif operation == '/':
            result /= num

end_time = time.time()
elapsed_time = end_time - start_time

print("Elapsed Time:", elapsed_time, "seconds")

decimalモジュールを利用した処理


import random
from decimal import Decimal, getcontext
import time

getcontext().prec = 28  # 精度を設定(必要に応じて調整してください)

random_numbers = [Decimal(random.random()) for _ in range(1000)]
operations = ['+', '-', '*', '/']
total_operations = 1000

start_time = time.time()

for _ in range(total_operations):
    result = random_numbers[0]
    for i in range(1, len(random_numbers)):
        operation = random.choice(operations)
        num = random_numbers[i]
        if operation == '+':
            result += num
        elif operation == '-':
            result -= num
        elif operation == '*':
            result *= num
        elif operation == '/':
            result /= num

end_time = time.time()
elapsed_time = end_time - start_time

print("Elapsed Time:", elapsed_time, "seconds")

fractionモジュールを利用した処理


import random
from fractions import Fraction
import time

random_numbers = [random.random() for _ in range(1000)]
operations = ['+', '-', '*', '/']
total_operations = 1000

start_time = time.time()

for _ in range(total_operations):
    result = Fraction(random_numbers[0])
    for i in range(1, len(random_numbers)):
        operation = random.choice(operations)
        num = Fraction(random_numbers[i])
        if operation == '+':
            result += num
        elif operation == '-':
            result -= num
        elif operation == '*':
            result *= num
        elif operation == '/':
            result /= num

end_time = time.time()
elapsed_time = end_time - start_time

print("Elapsed Time:", elapsed_time, "seconds")
    
結果:

以下のようになりました。floatとdecimalは、さほど差がないですが、fractionはかなり遅いことがわかります。

fractions : Elapsed Time: 80.84469294548035 seconds
float : Elapsed Time: 0.4394075870513916 seconds
decimal : Elapsed Time: 0.43607521057128906 seconds