2.

Python math.floor 完全ガイド(小数点以下切り捨て / 負数の挙動 / int との違い / numpy / 高速化)

編集
この記事の要点
  • math.floor(x)x 以下の最大の整数を返す関数(切り捨て)
  • 正の数では「小数部を捨てる」と同じ結果。負の数では int() や // と挙動が異なるので注意
  • 例: math.floor(-1.5) == -2int(-1.5) == -1(int は 0 方向への切り捨て)
  • Python 3 では戻り値は int 型。Python 2 系の float 戻り値とは異なる
  • 配列・ベクトル化処理には numpy.floor、四捨五入は round、上向き丸めは math.ceil

math.floor とは

math.floor(x) は引数 x 以下の最大の整数を返す関数です。数学的には床関数 ⌊x⌋ と表され、「小数点以下を切り捨てる」処理に近いですが、負の数では挙動が異なる点に注意が必要です。

基本構文

import math

math.floor(x)
項目内容
引数x: int / float / __floor__ を持つオブジェクト
戻り値int(Python 3 系)
例外x が数値でない場合 TypeError

基本例

import math

print(math.floor(3.7))    # 3
print(math.floor(3.0))    # 3
print(math.floor(-1.2))   # -2  ← 注意!
print(math.floor(-3.0))   # -3
print(math.floor(0.999))  # 0
print(math.floor(-0.001)) # -1

負の数で int() / // との違いに注意

Python で「切り捨て」と一括りに言っても、3 つの方法でそれぞれ結果が違います。

math.floor(x)int(x)x // 1
3.7333.0
3.0333.0
-1.2-2-1-2.0
-1.0-1-1-1.0
0.999000.0
-0.001-10-1.0
  • math.floor負の無限大方向へ丸める(数直線で小さい方)
  • int0 方向への切り捨て(truncation)
  • //(整数除算)は floor と同じ方向に丸める(float の戻り値)

戻り値の型

Python 3 系では math.floorint を返すようになりました(Python 2 では float)。配列のインデックスや整数演算にそのまま使えます。

x = 7.4
i = math.floor(x)
print(type(i))   # <class 'int'>
arr = [10, 20, 30, 40, 50]
print(arr[i])    # 80(インデックス 7 ではなく、ここでは IndexError になる例)

関連関数

関数意味2.5 / -2.5
math.floor負の無限大方向の整数2 / -3
math.ceil正の無限大方向の整数3 / -2
math.trunc0 方向の整数(int(x) と同じ)2 / -2
round偶数丸め(バンカーズラウンディング)2 / -2
int(x)0 方向に切り捨て + int キャスト2 / -2

「四捨五入したい」つもりで floor を使ってしまうとズレるので、目的に合わせて使い分けます。

numpy.floor との使い分け

配列に対して一度に切り捨てたい場合は numpy.floor が圧倒的に高速です。

import numpy as np

arr = np.array([1.2, -3.5, 0.99, -0.01])
print(np.floor(arr))
# [ 1. -4.  0. -1.]

numpy の戻り値は要素ごとに float のままです。int 配列にしたい場合は .astype(int) を追加します。

小数点以下 n 桁まで切り捨て

math.floor は整数化しかしないので、「小数第 2 位まで残して切り捨て」は 10 倍 → floor → 1/10 倍 のパターンで書きます。

import math

def floor_at(x, digits=2):
    factor = 10 ** digits
    return math.floor(x * factor) / factor

print(floor_at(3.14159, 2))   # 3.14
print(floor_at(-3.14159, 2))  # -3.15  ← floor なので負方向

Decimal での丸め

金額計算など丸め誤差が許されない場合は decimal.DecimalROUND_FLOOR を使うのが安全です。

from decimal import Decimal, ROUND_FLOOR

d = Decimal("3.14159")
print(d.quantize(Decimal("0.01"), rounding=ROUND_FLOOR))  # 3.14

d2 = Decimal("-3.14159")
print(d2.quantize(Decimal("0.01"), rounding=ROUND_FLOOR)) # -3.15

整数同士でも使える?

整数を渡すとそのまま返ります。「整数除算」と組み合わせたいときは // の方が自然です。

import math
print(math.floor(7))     # 7
print(math.floor(7 / 2)) # 3
print(7 // 2)            # 3 (同じ)
print(-7 // 2)           # -4 (math.floor(-3.5) と同じ)

カスタムクラスで floor を有効にする

自作クラスに __floor__ メソッドを定義すれば math.floor 対応にできます。

import math

class Money:
    def __init__(self, yen):
        self.yen = yen
    def __floor__(self):
        return Money(int(self.yen))  # 小数円を切り捨て

m = Money(123.7)
print(math.floor(m).yen)  # 123

よくある間違い

意図NGOK
四捨五入math.floor(x + 0.5)round(x) または math.floor(x + 0.5) は負数で破綻
0 方向に切り捨てmath.floor(x)math.trunc(x) / int(x)
配列に適用for で要素ごとに math.floornumpy.floor(arr)
「常に小数を捨てる」math.floor で十分と思い込む負数の挙動を理解して trunc と使い分け

FAQ

Q: float の精度誤差で floor が想定外になるのは?
A: 例えば math.floor(0.1 + 0.2)math.floor(0.30000000000000004) なので 0 になります。誤差が問題なら Decimal を使います。

Q: ceil とどう使い分ける?
A: 「ページ数 = 件数 / ページサイズ の切り上げ」は math.ceil、「経過時間からの完了ターン数」は math.floor など、丸める方向で選びます。

Q: 「半分は切り上げ・半分は切り捨て」のような丸めは?
A: それが round偶数丸めです。round(2.5)==2round(3.5)==4 となります。

関連

  • math — 親カテゴリ
  • math.ceil — 切り上げ
  • math.trunc / int() — 0 方向への切り捨て
  • round — 四捨五入(偶数丸め)
  • decimal モジュール — 高精度数値
編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. ceil
  2. floor

最近更新/作成されたページ