3-6. [参考] Pythonの浮動小数点演算の誤差


このページはPythonプログラミング学習入門編において、やや難易度が高いです。
理解が難しい時は立ち止まらずに、次の章に進みましょう。


1. 浮動小数点演算の誤差が生じる理由

3章でfloatは厳密な演算ができないケースがあることを説明しました。
例えば、 0.1 + 0.2 の演算結果は 0.3 ぴったりになりません。

print(0.1 + 0.2)
>> 0.30000000000000004



なぜ厳密にできないかというと、10進数の\frac{1}{10}をコンピューターが扱う2進数で表現できないからです。
この問題については、decimalモジュールを使うと厳密に計算できると説明しました。
しかし、decimalモジュールは計算スピードがfloat計算より遅いというデメリットがあります。

float型のデータをそのまま演算したい時に、取ることができる対処法について記載します。


2. 有効数字を決める

例えば、0.333333333333 を 0.333 で置き換えても、システムとして問題がない場合は有効数字3桁にして計算します。
つまり、十分に精度が高い桁数で結果が得られた後、最後に数字を丸める処理を実施します。


2-1. 小数を桁数指定して四捨五入で丸める

decimalモジュールで以下のように記載すると、対象の小数を指定した桁数で四捨五入ができます。

Decimal(str(対象の小数)).quantize(Decimal('<桁数がわかる数値>'), rounding=ROUND_HALF_UP)


これだけだと理解しにくいので、サンプルコードをみてください。

from decimal import Decimal, ROUND_HALF_UP

""" 
小数第一位を四捨五入して、整数で結果を取得する
"""
x = 10000.12345
round_result = Decimal(str(x)).quantize(Decimal('0'), rounding=ROUND_HALF_UP)

print(int(round_result)) # 整数型(int)に変換して表示する
>> 10000


""" 
小数第二位を四捨五入して、小数第一位までの結果を取得する
"""
x = 10000.12345
round_result = Decimal(str(x)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP)

print(float(round_result)) # 浮動小数点数型(float)に変換して表示する
>> 10000.1


""" 
小数第五位を四捨五入して、小数第四位までの結果を取得する
"""
x = 10000.12345
round_result = Decimal(str(x)).quantize(Decimal('0.0001'), rounding=ROUND_HALF_UP)

print(float(round_result)) # 浮動小数点数型(float)に変換して表示する
>> 10000.1235


2-2. 小数を切り捨て・切り上げで丸めて整数にする

mathモジュールで以下のように記載すると、対象の小数を切り捨て・切り上げで整数にできる。

  • 切り捨て : math.floor(<対象の小数>)
  • 切り上げ : math.ceil(<対象の小数>)

これだけだと理解しにくいので、サンプルコードをみてください。

import math

print(math.floor(2.7)) # 切り捨てて整数
>> 2 

print(math.ceil(2.7)) # 切り上げて整数
>> 3 

このエントリーをはてなブックマークに追加