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

あわせて読みたい

プログラミング学習に興味がある方は、まずは無料体験会へ

無料体験会・お申し込みはこちら