Pythonで小数点を自在に操作!math.floor()とmath.ceil()で切り捨て・切り上げ
Pythonで数値を扱う際、小数点以下を切り捨てたり、切り上げたりする操作は非常によく行われます。組み込み関数だけでは難しいこれらの処理も、mathモジュールのmath.floor()とmath.ceil()を使えば簡単に実現できます。この記事では、これらの関数の使い方と、具体的なコード例を交えて詳しく解説します。
小数点以下を切り捨てる:math.floor()
math.floor()関数は、与えられた数値以下の最大の整数を返します。つまり、小数点以下を切り捨てる効果があります。
math.floor()の基本的な使い方
math.floor()は、正の数に対しても負の数に対しても、常に「与えられた数以下で最も大きい整数」を返します。
import math
# math.floor()の基本的な使い方
print(math.floor(3.14)) # 3
print(math.floor(3.99)) # 3
print(math.floor(-2.1)) # -3 (例: -2.1以下の最大の整数は-3)
正の数の場合は一般的な切り捨てと同じ動作になりますが、負の数の場合は注意が必要です。例えば、-2.1のmath.floor()は-3になります。これは、数直線上で-2.1の左側にある最も近い整数が-3だからです。
↑ 小数点以下を切り上げる:math.ceil()
一方、math.ceil()関数は、与えられた数値以上の最小の整数を返します。これは小数点以下を切り上げる操作に相当します。
math.ceil()の基本的な使い方
math.ceil()は、正の数に対しても負の数に対しても、常に「与えられた数以上で最も小さい整数」を返します。
import math
# math.ceil()の基本的な使い方
print(math.ceil(3.14)) # 4
print(math.ceil(3.01)) # 4
print(math.ceil(-2.9)) # -2 (例: -2.9以上の最小の整数は-2)
こちらも負の数の場合に注意が必要です。-2.9のmath.ceil()は-2になります。これは、数直線上で-2.9の右側にある最も近い整数が-2だからです。
int()関数との違い
Pythonの組み込み関数であるint()も小数点を扱えますが、これは常に小数点以下を切り捨てるわけではありません。int()は、数値を整数型に変換する際にゼロ方向へ丸めます。
int()とmath.floor()の違い
正の数の場合はint()とmath.floor()は同じ結果になりますが、負の数の場合は結果が異なります。
import math
# int()とmath.floor()の違い
print(int(3.8)) # 3
print(math.floor(3.8)) # 3
print(int(-3.8)) # -3 (ゼロ方向へ丸める)
print(math.floor(-3.8)) # -4 (数直線上で-3.8以下の最大の整数)
この違いを理解しておくことは、意図しない結果を避けるために重要です。
まとめ
Pythonで小数点以下を切り捨てたい場合はmath.floor()を、切り上げたい場合はmath.ceil()を使用しましょう。特に負の数を扱う際には、int()関数との違いを意識することが大切です。これらの関数を使いこなすことで、数値処理の柔軟性が大きく向上します。
math.trunc()を加えた3つの比較
切り捨て・切り上げには、もう1つmath.trunc()という選択肢があります。3つをまとめて比較すると、違いがはっきりします。
import math
for x in [3.7, 3.2, -3.2, -3.7]:
print(f"{x:>6} floor={math.floor(x):>3} ceil={math.ceil(x):>3} trunc={math.trunc(x):>3}")
実行結果:
3.7 floor= 3 ceil= 4 trunc= 3
3.2 floor= 3 ceil= 4 trunc= 3
-3.2 floor= -4 ceil= -3 trunc= -3
-3.7 floor= -4 ceil= -3 trunc= -3
| 関数 | 正の数 | 負の数 | 動きの方向 |
|---|---|---|---|
math.floor() |
切り捨て | 切り下げ | 常に小さい方へ |
math.ceil() |
切り上げ | 切り上げ | 常に大きい方へ |
math.trunc() |
切り捨て | 切り上げ | 常に0の方へ |
負の数でtrunc()はceil()と同じ結果になる点が、意外に思われるかもしれません。「小数部分をそのまま捨てる」と、負の数では値が大きくなるためです。
切り上げ除算のイディオム
「120個を1箱50個で詰めると何箱必要か」のような計算では、切り上げが必要です。
import math
items = 120
per_box = 50
print(math.ceil(items / per_box))
実行結果:
3
これで正しく動きますが、巨大な整数では誤差が出る可能性があります。割り算の時点でfloatに変換されるためです。
import math
a = 10 ** 20 + 1
b = 10 ** 20
print(math.ceil(a / b))
print(-(-a // b))
実行結果:
1
2
正しいのは2です。math.ceil(a / b)は、割り算の結果が1.0に丸められてしまうため誤ります。
-(-a // b)というイディオムなら、整数のまま計算するので正確です。
def ceil_div(a, b):
return -(-a // b)
print(ceil_div(120, 50))
print(ceil_div(100, 50))
print(ceil_div(1, 50))
実行結果:
3
2
1
仕組みは単純です。//は切り捨て除算なので、符号を反転してから割り、結果をもう一度反転すると切り上げになります。
小さな数ならmath.ceil()で十分読みやすいので、巨大な整数を扱う場合だけこのイディオムを思い出してください。
実践例|ページネーション
import math
def total_pages(total_items, per_page):
return math.ceil(total_items / per_page)
for n in [0, 1, 10, 11, 100]:
print(f"{n:>4}件 → {total_pages(n, 10)}ページ")
実行結果:
0件 → 0ページ
1件 → 1ページ
10件 → 1ページ
11件 → 2ページ
100件 → 10ページ
「11件を10件ずつ表示するなら2ページ必要」という計算です。切り上げを使う代表例で、Web開発では頻出します。
実践例|必要な人数・時間を求める
import math
def required_workers(tasks, capacity):
return math.ceil(tasks / capacity)
def elapsed_minutes(seconds):
return math.floor(seconds / 60)
print("必要人数:", required_workers(47, 8), "人")
print("経過時間:", elapsed_minutes(119), "分")
実行結果:
必要人数: 6 人
経過時間: 1 分
「足りないと困るもの」は切り上げ、「経過した分だけ数えるもの」は切り捨て——業務ルールに合わせて選ぶのがポイントです。
桁数を指定して丸める
import math
def ceil_at(x, digits=0):
p = 10 ** digits
return math.ceil(x * p) / p
def floor_at(x, digits=0):
p = 10 ** digits
return math.floor(x * p) / p
print(ceil_at(3.141, 2))
print(floor_at(3.149, 2))
実行結果:
3.15
3.14
金額など誤差が許されない計算では、decimalモジュールを使うほうが安全です。
from decimal import Decimal, ROUND_CEILING, ROUND_FLOOR
x = Decimal("3.141")
print(x.quantize(Decimal("0.01"), rounding=ROUND_CEILING))
print(x.quantize(Decimal("0.01"), rounding=ROUND_FLOOR))
実行結果:
3.15
3.14






