Python decimalの丸めモード8種類|ROUND_HALF_UPで四捨五入・ROUND_DOWNとROUND_FLOORの違い
Pythonの decimal で四捨五入するには、Decimal("2.5").quantize(Decimal("1"), rounding=ROUND_HALF_UP) のように丸めモード ROUND_HALF_UP を指定します。指定しないと既定の ROUND_HALF_EVEN(偶数丸め)になり、2.5は3ではなく2になります。
この記事では、decimal の丸めモード8種類すべての違いを1つの表で確かめ、「切り捨て」の ROUND_DOWN と ROUND_FLOOR の違い、わかりにくい ROUND_05UP、丸めモードを指定する3つの場所(quantize()・コンテキスト・round())を説明します。round() を含めた四捨五入の方法全体はPythonで四捨五入する方法|round()が偶数丸めになる理由とDecimalの使い分けにまとめています。
コードはPython 3.14.8で実行しました。各モードの定義はdecimal モジュールの公式ドキュメントで確認しています(2026年10月18日確認)。
丸めモード8種類の一覧と実行結果
6つの値を、すべてのモードで整数に丸めました。
from decimal import (Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_HALF_DOWN,
ROUND_UP, ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR, ROUND_05UP)
modes = [ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_HALF_DOWN, ROUND_UP,
ROUND_DOWN, ROUND_CEILING, ROUND_FLOOR, ROUND_05UP]
values = ["2.5", "3.5", "2.4", "2.6", "-2.5", "-2.6"]
print("モード".ljust(16), *[v.rjust(5) for v in values])
for m in modes:
row = [str(Decimal(v).quantize(Decimal("1"), rounding=m)).rjust(5) for v in values]
print(m.ljust(16), *row)
モード 2.5 3.5 2.4 2.6 -2.5 -2.6
ROUND_HALF_UP 3 4 2 3 -3 -3
ROUND_HALF_EVEN 2 4 2 3 -2 -3
ROUND_HALF_DOWN 2 3 2 3 -2 -3
ROUND_UP 3 4 3 3 -3 -3
ROUND_DOWN 2 3 2 2 -2 -2
ROUND_CEILING 3 4 3 3 -2 -2
ROUND_FLOOR 2 3 2 2 -3 -3
ROUND_05UP 2 3 2 2 -2 -2
この結果と公式ドキュメントの定義を、日本語でまとめると次のようになります。
| モード | 公式の定義(要約) | 日本語でいうと |
|---|---|---|
ROUND_HALF_UP |
最も近い値へ。ちょうど半分なら0から遠い方へ | 四捨五入 |
ROUND_HALF_EVEN |
最も近い値へ。ちょうど半分なら偶数の方へ | 偶数丸め(銀行丸め)。decimalの既定 |
ROUND_HALF_DOWN |
最も近い値へ。ちょうど半分なら0の方へ | 五捨六入 |
ROUND_UP |
0から遠い方へ | 切り上げ(絶対値を大きく) |
ROUND_DOWN |
0の方へ | 切り捨て(絶対値を小さく) |
ROUND_CEILING |
正の無限大の方へ | 数直線で上へ(math.ceil と同じ向き) |
ROUND_FLOOR |
負の無限大の方へ | 数直線で下へ(math.floor と同じ向き) |
ROUND_05UP |
0の方へ丸めた結果の最後の桁が0か5なら0から遠い方へ、それ以外は0の方へ | 特殊な用途向け(後述) |
「HALF」が付く3つは、ちょうど半分(2.5や-2.5)のときだけ動きが分かれます。2.4や2.6のように半分でない値では、3つとも同じ結果です。
ROUND_HALF_UP で四捨五入する(小数第n位まで)
quantize() に渡す Decimal の桁で、どこまで残すかを決めます。
from decimal import Decimal, ROUND_HALF_UP
x = Decimal("1234.5678")
print(x.quantize(Decimal("1"), rounding=ROUND_HALF_UP))
print(x.quantize(Decimal("0.1"), rounding=ROUND_HALF_UP))
print(x.quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(x.quantize(Decimal("1E+2"), rounding=ROUND_HALF_UP))
1235
1234.6
1234.57
1.2E+3
Decimal("1") で整数、Decimal("0.01") で小数第2位までになります。最後の行のように、百の位で丸めると 1.2E+3(1200)という指数表記になる点に注意してください。quantize() の使い方そのものはDecimalのquantize()の解説で詳しく説明しています。
Decimal は文字列から作る
丸めモードを正しく選んでも、Decimal をfloatから作ると結果がずれます。
from decimal import Decimal, ROUND_HALF_UP
print(Decimal(2.675))
print(Decimal(2.675).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(Decimal("2.675").quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
print(Decimal(str(2.675)).quantize(Decimal("0.01"), rounding=ROUND_HALF_UP))
2.67499999999999982236431605997495353221893310546875
2.67
2.68
2.68
floatの2.675は内部では2.67499…なので、ROUND_HALF_UP でも2.67になります。Decimal("2.675") のように文字列から作るか、すでにfloatになっている値は str() を通してから渡します。理由はDecimal()を文字列から作るべき理由で説明しています。
ROUND_DOWN と ROUND_FLOOR の違い(マイナスで差が出る)
正の数ではどちらも「切り捨て」に見えますが、負の数では結果が変わります。返金額のようなマイナスの金額で試しました。
from decimal import Decimal, ROUND_DOWN, ROUND_FLOOR
refund = Decimal("-123.45")
print(refund.quantize(Decimal("1"), rounding=ROUND_DOWN))
print(refund.quantize(Decimal("1"), rounding=ROUND_FLOOR))
-123
-124
| 考え方 | 小さくする側 | 大きくする側 |
|---|---|---|
| 0からの距離で考える | ROUND_DOWN(0へ近づける) |
ROUND_UP(0から遠ざける) |
| 数直線の向きで考える | ROUND_FLOOR(下へ) |
ROUND_CEILING(上へ) |
仕様書で「切り捨て」と書かれていたら、マイナスのときに0へ寄せるのか(ROUND_DOWN)、小さい方へ寄せるのか(ROUND_FLOOR)を確認しておくと、あとで金額が1円ずれる事故を防げます。
ROUND_05UP はどんな丸め方か
ROUND_05UP は、いったん0の方へ切り捨て、その結果の最後の桁が0か5のときだけ0から遠い方へずらします。
from decimal import Decimal, ROUND_05UP
for v in ["0.3", "4.3", "5.3", "10.3", "-5.3"]:
print(v, "->", Decimal(v).quantize(Decimal("1"), rounding=ROUND_05UP))
0.3 -> 1
4.3 -> 4
5.3 -> 6
10.3 -> 11
-5.3 -> -6
4.3は切り捨てると4(最後の桁が4)なのでそのまま4、5.3は切り捨てると5(最後の桁が5)なので6になります。金額の端数処理のような普段の計算で使う場面はまずありません。業務の計算で迷ったら、ほかの7つから選んでください。
丸めモードを指定する3つの場所
1. quantize() の rounding 引数(おすすめ)
これまでの例のように、quantize() の呼び出しごとに rounding= を渡す方法です。その行だけを読めばどう丸めるかがわかるので、最も間違いが起きにくい書き方です。rounding を省略すると、次のコンテキストの設定が使われます。
2. コンテキスト(getcontext / localcontext)
getcontext().rounding を変えると、そのスレッドで以後の既定の丸め方が変わります。範囲を限りたいときは localcontext() を with 文で使います。Python 3.11以降は、キーワード引数で localcontext(rounding=...) と書けます。
from decimal import Decimal, localcontext, ROUND_HALF_UP, getcontext
with localcontext(rounding=ROUND_HALF_UP):
print(Decimal("2.5").quantize(Decimal("1")))
print(Decimal("2.5").quantize(Decimal("1")))
print(getcontext().rounding)
3
2
ROUND_HALF_EVEN
with を抜けると、既定の ROUND_HALF_EVEN に戻っています。
コンテキストの丸めモードは、quantize() だけでなく割り算などの計算結果を有効桁数(prec)に収めるときにも使われます。
from decimal import Decimal, getcontext, ROUND_DOWN
getcontext().prec = 5
print(Decimal("1") / Decimal("3"))
print(Decimal("2") / Decimal("3"))
getcontext().rounding = ROUND_DOWN
print(Decimal("2") / Decimal("3"))
0.33333
0.66667
0.66666
このように、getcontext().rounding をプログラムの途中で変えると、無関係な計算の結果まで変わります。有効桁数の設定についてはgetcontext()の解説をご覧ください。
3. round() 関数(引数の数で動きが違う)
Decimal にも組み込みの round() が使えますが、桁数を渡すかどうかで丸めモードの扱いが変わります。コンテキストを ROUND_HALF_UP にして試しました。
from decimal import Decimal, getcontext, ROUND_HALF_UP
getcontext().rounding = ROUND_HALF_UP
print(round(Decimal("2.5")), round(Decimal("3.5")))
print(round(Decimal("2.665"), 2))
print(Decimal("2.5").quantize(Decimal("1")))
print(Decimal("2.5").to_integral_value())
2 4
2.67
3
3
1行目は ROUND_HALF_UP にしたのに2と4(偶数丸め)のままです。公式ドキュメントにも、round(number) のように桁数を渡さないときはコンテキストの丸めモードを無視して偶数丸めで整数を返し、round(number, ndigits) のときはコンテキストの丸めモードに従う、と書かれています。整数に丸めたいときは、round() ではなく quantize(Decimal("1"), rounding=...) を使うのが確実です。
やりたいこと別の書き方
| やりたいこと | 書き方(q = Decimal("0.01") で小数第2位まで) |
|---|---|
| 四捨五入 | x.quantize(q, rounding=ROUND_HALF_UP) |
| 切り捨て(0へ寄せる) | x.quantize(q, rounding=ROUND_DOWN) |
| 切り上げ(0から離す) | x.quantize(q, rounding=ROUND_UP) |
| 常に小さい方へ | x.quantize(q, rounding=ROUND_FLOOR) |
| 常に大きい方へ | x.quantize(q, rounding=ROUND_CEILING) |
| 偶数丸め(既定) | x.quantize(q) または rounding=ROUND_HALF_EVEN |
| 一時的に既定を変える | with localcontext(rounding=ROUND_HALF_UP): |
よくある質問
Q. Decimal の既定の丸めモードは何ですか?
ROUND_HALF_EVEN(偶数丸め)です。getcontext().rounding で確認でき、ちょうど半分のときは偶数の方へ丸めるため、Decimal(“2.5”) を整数に丸めると2になります。
Q. ROUND_DOWN と ROUND_FLOOR の違いは何ですか?
ROUND_DOWN は0の方へ、ROUND_FLOOR は負の無限大の方へ丸めます。正の数では同じ結果ですが、-123.45 を整数にすると ROUND_DOWN は -123、ROUND_FLOOR は -124 になります。
Q. getcontext().rounding を ROUND_HALF_UP にしたのに round(Decimal(“2.5”)) が2になります。
桁数を渡さない round() は、コンテキストの丸めモードを無視して偶数丸めで整数を返す仕様です。整数に丸めるときは quantize(Decimal(“1”), rounding=ROUND_HALF_UP) を使います。
Q. ROUND_HALF_UP にしたのに 2.675 が 2.67 になります。
Decimal を float から作っているためです。float の 2.675 は内部では 2.67499… なので、Decimal(“2.675”) のように文字列から作ってください。
まとめ
decimal の丸めモードは8種類あり、既定は四捨五入ではなく ROUND_HALF_EVEN です。四捨五入なら ROUND_HALF_UP、マイナスを含む切り捨てなら ROUND_DOWN と ROUND_FLOOR のどちらが要件に合うかを確認し、丸めモードは quantize() の rounding= で毎回明示するのが安全です。
数値の扱いのような基礎は、実際に動かして確かめるのがいちばんの近道です。テックジムは対面・通学型のプログラミングスクールで、東京本校(永田町)では自分のペースで課題を進め、詰まったらトレーナーに質問できます。無料Python講座もあります。




