Pythonで小数点以下を切り捨て・切り上げ: math.floor(), math.ceil()

Modified: | Tags: Python, 数値

Pythonで浮動小数点数floatの小数点以下を切り捨て・切り上げするには、標準ライブラリmathモジュールのfloor(), ceil()を使う。

なお、厳密にはmath.floor()は「負の無限大への丸め」、math.ceil()は「正の無限大への丸め」となる。負の値を処理する際は注意。

先に結果をまとめておくと以下の通り。「0への丸め」にはint()を使えるが、「無限大への丸め」については関数を定義する必要がある。詳細は後述。

print(math.floor(10.123))
# 10

print(math.floor(-10.123))
# -11

print(math.ceil(10.123))
# 11

print(math.ceil(-10.123))
# -10

print(int(10.123))
# 10

print(int(-10.123))
# -10

また、四捨五入には組み込み関数round()や標準ライブラリdecimalのquantize()を使う。詳細は以下の記事を参照。

NumPy配列ndarrayの要素に対して小数点以下の切り捨て・切り上げをしたい場合は以下の記事を参照。

小数点以下を切り捨て: math.floor()

小数点以下を切り捨てるにはmath.floor()を使う。整数intが返される。

import math

print(math.floor(10.123))
# 10

print(math.floor(10.987))
# 10

print(type(math.floor(10.123)))
# <class 'int'>

整数intの場合は値がそのまま返される。文字列strなど、特殊メソッド__floor__()が定義されていないクラスのオブジェクトはエラーとなる。

print(math.floor(10))
# 10

# print(math.floor('10'))
# TypeError: must be real number, not str

print(hasattr(10, '__floor__'))
# True

print(hasattr('10', '__floor__'))
# False

math.floor(x)が返すのは「xの『床』(x以下の最大の整数)」であり、「負の無限大への丸め (rounding toward minus infinity; RM)」となるため、負の値に対しては以下のような結果となる。

print(math.floor(-10.123))
# -11

print(math.floor(-10.987))
# -11

符号はそのままで絶対値を切り捨てたい、すなわち「0への丸め (rounding toward zero; RZ)」を実現したい場合はint()を使う。後述。

小数点以下を切り上げ: math.ceil()

小数点以下を切り上げるにはmath.ceil()を使う。整数intが返される。

import math

print(math.ceil(10.123))
# 11

print(math.ceil(10.987))
# 11

print(type(math.ceil(10.123)))
# <class 'int'>
source: math_ceil.py

整数intの場合は値がそのまま返される。文字列strなど、特殊メソッド__ceil__()が定義されていないクラスのオブジェクトはエラーとなる。

print(math.ceil(10))
# 10

# print(math.ceil('10'))
# TypeError: must be real number, not str

print(hasattr(10, '__ceil__'))
# True

print(hasattr('10', '__ceil__'))
# False
source: math_ceil.py

math.ceil(x)が返すのは「xの『天井』(x以上の最小の整数)」であり、「正の無限大への丸め (rounding toward plus infinity; RP)」となるため、負の値に対しては以下のような結果となる。

print(math.ceil(-10.123))
# -10

print(math.ceil(-10.987))
# -10
source: math_ceil.py

符号はそのままで絶対値を切り上げたい、すなわち「無限大への丸め (rounding toward infinity; RI)」を実現したい場合については新たな関数を定義する必要がある。後述。

math.floor()とint()との違い

小数点以下の切り捨てにはint()を使うことも可能。

正の数値に対してはmath.floor()と同じ結果を返す。返り値は整数int

print(int(10.123))
# 10

print(int(10.987))
# 10

print(int(10))
# 10

print(type(int(10.123)))
# <class 'int'>

負の数値に対してはmath.floor()と結果が異なる。

math.floor()が「負の無限大への丸め (rounding toward minus infinity; RM)」であるのに対し、int()は「0への丸め (rounding toward zero; RZ)」となる。int()では常に0に近づく方に丸められる。

print(int(-10.123))
# -10

print(int(-10.987))
# -10

そのほか、int()は文字列strも処理できる。小数を表す文字列は変換できないが、第二引数baseを指定することで2進数や16進数表記の整数の文字列を変換することもできる。

print(int('10'))
# 10

# print(int('10.123'))
# ValueError: invalid literal for int() with base 10: '10.123'

print(int('FF', 16))
# 255

無限大への丸め (rounding toward infinity; RI)

負の値を考慮すると、切り上げ・切り捨ては4種類ある。

上述のように、それぞれ以下の関数で実現できる。

  • 負の無限大への丸め: math.floor()
  • 正の無限大への丸め: math.ceil()
  • 0への丸め: int()
  • 無限大への丸め
print(math.floor(10.123))
# 10

print(math.floor(-10.123))
# -11

print(math.ceil(10.123))
# 11

print(math.ceil(-10.123))
# -10

print(int(10.123))
# 10

print(int(-10.123))
# -10

「無限大への丸め (rounding toward infinity; RI)」については、例えば以下のような関数で実現できる(もっといい方法があるかもしれない)。

def round_towards_infinity(x):
    return int(math.copysign(math.ceil(abs(x)), x))

print(round_towards_infinity(10.123))
# 11

print(round_towards_infinity(-10.123))
# -11

abs()による絶対値をmath.ceil()で切り上げて、math.copysign()で元の値と同じ符号に戻す。math.copysign()は浮動小数点数floatを返すので、int()で整数intに変換している。

関連カテゴリー

関連記事