Python - 小数・整数を四捨五入する

四捨五入する: round() 関数

Python には組み込み関数として round() 関数が用意されています。

round(number[, ndigits])
round() 関数の構文

round() 関数では、第一引数 (number) に四捨五入したい数値を指定し、オプショナルの第二引数には何桁にするか指定します。第二引数が省略された場合、入力値にもっとも近い整数 (int) を返します。第二引数が指定された場合、浮動小数点数 (float) を返します。ただし、round() 関数は厳密な四捨五入ではなく、偶数への丸めである点に注意してください。偶数への丸めについては後述します。

f = 123.456

print(round(f))
# 123

print(type(round(f)))
# <class 'int'>

print(round(f, 1))
# 123.5

print(round(f, 2))
# 123.46

print(round(f, 0))
# 123.0

print(type(round(f, 0)))
# <class 'float'>
round() 関数の四捨五入

第二引数に負の整数を指定した場合、対応する桁に丸めることができます。

i = 123

print(round(i, -1))
# 120

print(round(i, -2))
# 100

f = 123.456

print(round(f, -1))
# 120.0

print(round(f, -2))
# 100.0
round() 関数の四捨五入

偶数への丸めとは、端数が 0.5 より小さいなら切り捨て、端数が 0.5 より大きいならは切り上げ、端数がちょうど 0.5 なら切り捨てと切り上げのうち結果が偶数となる方へ丸める方法です。つまり端数がちょうど 0.5 の場合、以下のように結果はすべて偶数となります。

print(round(0.5)) # 0
print(round(1.5)) # 2
print(round(2.5)) # 2
print(round(3.5)) # 4
print(round(4.5)) # 4
偶数への丸め

ただし、2進数では小数点以下を浮動小数点数では正確に表現できないため、小数点以下2桁以降の処理では偶数への丸めの定義に当てはまらない場合があるので注意が必要です。

print(round(0.05, 1)) # 0.1
print(round(0.15, 1)) # 0.1
print(round(0.25, 1)) # 0.2
print(round(0.35, 1)) # 0.3
print(round(0.45, 1)) # 0.5
偶数への丸め

正確な偶数への丸めを実現したい場合は、次の decimal.quantize() 関数か、新しい関数を定義する方法を使います。また、Python2 の round() は偶数の丸めではなく四捨五入の処理となるため、注意してください。

四捨五入する: decimal.quantize() 関数

標準ライブラリの decimal モジュールを使うと、正確な十進浮動小数点数を扱うことができます。

decimal モジュールの quantize() 関数を使うと、丸めモードを指定して数値を丸めることができます。

quantize(exp, rounding=None, context=None)
quantize() 関数の構文

quantize() 関数の rounding 引数に、ROUND_HALF_UP を指定すると一般的な四捨五入になります。

from decimal import Decimal, ROUND_HALF_UP

print(Decimal('1.5').quantize(Decimal('1'), ROUND_HALF_UP))
# 2
quantize() 関数での四捨五入

Decimal()Decimal 型のオブジェクトを生成できます。引数に float 型を指定すると、実際に扱われる数値について確認することができます。

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>
Decimal 型のオブジェクト

上記のように、0.05 は2進数で正確には表現できないため、近似値となります。上述した round 関数で 0.05 を含む数値が正しく丸められなかったのは、これが原因になります。

引数に float 型ではなく str 型を指定すると、正確にその値の Decimal 型として扱われます。

print(Decimal('0.05'))
# 0.05
Decimal 型のオブジェクト

quantize() の第一引数に求めたい桁数と同じ桁数の数値を '0.1''0.01' のように文字列で指定します。引数 rounding には、丸めモードを指定します。例えば、ROUND_HALF_UP を丸めモードとして指定すると、一般的な四捨五入となります。

from decimal import Decimal, ROUND_HALF_UP

f = 123.456

print(Decimal(str(f)).quantize(Decimal('0'),    rounding=ROUND_HALF_UP)) # 123
print(Decimal(str(f)).quantize(Decimal('0.1'),  rounding=ROUND_HALF_UP)) # 123.5
print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 123.46
quantize() 関数での四捨五入

組み込み関数 round() と異なり、0.51 に丸められています。

from decimal import Decimal, ROUND_HALF_UP

print(Decimal('0.4').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 0
print(Decimal('0.5').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 1
print(Decimal('0.6').quantize(Decimal('0'), rounding=ROUND_HALF_UP)) # 1
quantize() 関数での四捨五入

四捨五入する: decimal.as_tuple() 関数

整数を任意の桁数で四捨五入する場合、as_tuple() 関数を使います。また、整数 (Decimal('10')) の場合、E を使った指数表記になります。四捨五入を行う場合は、引数の roundingROUND_HALF_UP を指定します。ただし、そのままでは結果も指数表記になるため、整数として演算したい場合、int() で変換する必要があります。

i = 12345

print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))
# 1.235E+4

print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 12350

print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP)))
# 12300

print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP)))
# 12000
as_tuple() 関数での四捨五入

整数の場合、浮動小数点数とは異なり指数表記になる理由は、整数 (Decimal('10')) では Decimal オブジェクトの指数 (exponent) が 1 ではなく 0 になるためです。

print(Decimal('10').as_tuple())
# DecimalTuple(sign=0, digits=(1, 0), exponent=0)

print(Decimal('1E1').as_tuple())
# DecimalTuple(sign=0, digits=(1,), exponent=1)
as_tuple() 関数での四捨五入

関連記事