Decimal class in Python
Series Overview
This article is part of the series. Below are links to all posts in the series:- How to use Python Decimal class
- Fix floating point precision errors Python
- Decimal vs float Python comparison
- How to handle money calculations Python
- Tolerance-based comparisons
Floating Away: Slightly Unstable World of Real Number Computations. Using Decimal class in Python.
We had a discussion about the reasons behind rounding errors and floating-point arithmetic. It’s time to solve them.
In most cases, it’s acceptable to use float and double datatypes for your computations. However, there might be a few cases that require accuracy. At least, money computations.
There are special types that are intended to help you with that. In this post, we are working with Decimal class.
Let’s create the price and tax_rate variables in Python:
price: float = 19.99
tax_rate: float = 0.075
Then, some computations:
tax_amount = price * tax_rate
total_price = price + tax_amount
If you print tax_amount and total_price, you get:
1.4992499999999997
21.48925
As you see, the tax_amount value is not correct. The reason is rounding errors. We can fix that by using decimal.Decimal class:
price = Decimal("19.99")
tax_rate = Decimal("0.075")
Crucial that you should use strings to initialize Decimal! If you used constructor like this: Decimal(19.99), results won’t change.
The rest of the code remains the same. The Output this time will be:
1.49925
21.48925
Also, you should avoid direct comparison of float-point numbers:
a: float = 0.1 + 0.2
b: float = 0.3
print(a == b) # Output: false
Instead, we should use Decimal objects initialized with strings (!):
a1 = Decimal("0.1") + Decimal("0.2")
b1 = Decimal("0.3")
print(a1 == b1) # Output: true
Or tolerance-based comparisons:
a = 0.1 + 0.2
b = 0.3
epsilon = 1e-10
print(abs(a - b) < epsilon)