DEV Community

Serhat Teker
Serhat Teker

Posted on Originally published at tech.serhatteker.com on

Decimal Precision and Rounding in Python

If you need precision in your project you should use decimal —decimal module, since float data type has some issues and limitations as you can see here: floating issues.

To use decimal as described here decimal tutorial:

from decimal import Decimal


number = Decimal("0.976815352")
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

OK, if I want some specific precision what should I do? With float it's something like:

number = 0.976815352
rounded_number = (number, '.2f')
# or
print(f"rounded_number = {x:.2f}")
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

With decimal:

from decimal import getcontext, Decimal


getcontext().prec = 3
result = Decimal("0.976815352") / Decimal("2.42532")

print(result)
# 0.403
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

will give 0.403. It seems OK. However if you try

result = Decimal('3.1415926535') + Decimal('2.7182818285')

print(result)
# 5.86
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

will give 5.86 and you'll probably say wth. It's because in decimal, precision means precision including the digits before decimal/dot.

So how is it possible to know the digits of a decimal among thousands, e.g. price between ∞ and 0.00000001?

After a lot of researching, a.k.a. stackoverflowing, I came across to this: gist.

Precision & Rounding

Option 1 - Round Decimal Using round()

from decimal import Decimal


result = Decimal('3.1415926535') + Decimal('2.7182818285')
result = round(x, 2)

print(result)
# Output: 5.86
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

Option 2 - Use Decimal Module's Roundings

from decimal import Decimal, ROUND_HALF_UP
# All options for rounding:
# ROUND_05UP       ROUND_DOWN       ROUND_HALF_DOWN  ROUND_HALF_UP
# ROUND_CEILING    ROUND_FLOOR      ROUND_HALF_EVEN  ROUND_UP


result = Decimal('3.1415926535') + Decimal('2.7182818285')
result = Decimal(our_value.quantize(Decimal('.01'), rounding=ROUND_HALF_UP))

print(result)
# Output: 5.86
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

We use "0.01" as round to 2 digits decimal.

Option 3 - Setting Getcontext Precision

We saw this one in the beginning and it gave us wth:

from decimal import getcontext, Decimal


getcontext().prec = 2
result = Decimal('3.1415926535') + Decimal('2.7182818285')

print(result)
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

So better not to chose because of confusion.

Option 4 (Preferred Option)

After reading some comments on the gist I found my ultimate solution. It
comes from py-moneyd library:

def round(self: M, ndigits: Optional[int] = 0) -> M:
    """
    Rounds the amount using the current ``Decimal`` rounding algorithm.
    """
    if ndigits is None:
        ndigits = 0
    return self.__class__(
        amount=self.amount.quantize(Decimal("1e" + str(-ndigits))),
        currency=self.currency,
    )
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

I did some tweaks for generalization and I wrote this helper method:

from decimal import Decimal


class Acccounting:
    def round(self, amount: str, ndigits: int) -> Decimal:
        """ Rounds the amount using the current `Decimal` rounding algorithm. """
        if ndigits is None:
            ndigits = 0
        return Decimal(
            Decimal(amount).quantize(Decimal("1e" + str(-ndigits))),
        )
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

In order to round 2 with this helper:

from decimal import Decimal
from .helpers import Acccounting


result = Decimal('3.1415926535') + Decimal('2.7182818285')
result = Acccounting().round(amount=result, ndigits=2)

print(result)
# Output: 5.86
✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025 ✨ อัปเดตล่าสุด: serhatteker/decimal precision and rounding in python md - Kapook Update 2025

Thanks a lot to @jackiekazil !

All done!

Top comments (0)