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")
``````

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}")
``````

With `decimal`:

``````from decimal import getcontext, Decimal

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

print(result)
# 0.403
``````

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

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

print(result)
# 5.86
``````

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
``````

`Decimal` has better `rounding`methods. See below;

### 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(result.quantize(Decimal('.01'), rounding=ROUND_HALF_UP))

print(result)
# Output: 5.86
``````

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)
# Output: 5.86
``````

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,
)
``````

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

``````from decimal import Decimal
from typing import Optional

class Acccounting:
"""General class for money operations"""

@classmethod
def round(self, amount: str, ndigits: Optional[int] = 0) -> 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))),
)
``````

In order to round 2 with this helper:

``````from decimal import Decimal
from helpers.money import Acccounting

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

print(result)
# Output: 5.86
``````

Thanks a lot to @jackiekazil !

All done!

Changelog

• 2021-12-02 :
• Make `round` `classmethod`
• Fix missing var `result`
• Update import path for helper module