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講座もあります。

あわせて読みたい

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

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