Python has numeric data types like int, float and complex numbers but due to the machine dependent nature of floating point numbers, we need a more precise data type for calculations which demand high precision. In this article, we will study about the decimal module in python which implements the decimal numbers having precision of upto 28 digits.
When should we use decimal instead of float in Python?
Python implements decimal numbers as double precision floating point numbers which are machine dependent. For calculations where precision is critical for business reasons, floating points numbers may cause errors when run on a different machine. Therefore, For such applications, we need a machine independent data type to implement decimal numbers which has been implemented using the decimal module in python. Also, decimal module has implementation of decimal number for a precision of upto 28 decimal digits while floating point numbers have only a precision of upto 18 digits. This can be observed in the following example.
import decimal
float_division=4/3
decimal_devision=decimal.Decimal(4)/decimal.Decimal(3)
print("Result for float division of 4 by 3:")
print(float_division)
print("Result for decimal division of 4 by 3:")
print(decimal_devision)
Output:
Result for float division of 4 by 3:
1.3333333333333333
Result for decimal division of 4 by 3:
1.333333333333333333333333333
The second reason to use decimals instead of floating point numbers is that numbers cannot be represented using their exact value in python and only an approximation is used which can be dangerous for critical programs.
Due to approximations, floating point values yield different results for different calculations. For example, if we add 1.2 and 2.2 using floating point values the answer should be equal to 3.4. But when we compare the added number and 3.4, it will not be equal. This error occurs because of the approximations in floating point numbers due to which sum of 1.2 and 2.2 is not equal to 3.4. So, In cases where decimal values need to be compared, we should use the decimal module instead of floating point numbers. This can be more clear from the following example.
x=1.2
y=2.2
z=3.4
a=x+y
print("x:",x)
print("y:",y)
print("z:",z)
print("x+y:",a)
print("x+y==z?:",a==z)
Output:
x: 1.2
y: 2.2
z: 3.4
x+y: 3.4000000000000004
x+y==z?: False
How to use the decimal module in Python?
To use the decimal module in python, we can import it as follows.
import decimal
The imported module has a predefined context which contains default values for precision, rounding, flags, minimum and maximum numbers allowed. We can look at the values of the context using the getcontext() method as follows.
import decimal
print(decimal.getcontext())
Output:
Context(prec=28, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])
We can also set the precision and other parameters of the context. To change the precision to 3 digits instead of 28, we can use the following program.
import decimal
decimal.getcontext().prec=3
print(decimal.getcontext())
Output:
Context(prec=3, rounding=ROUND_HALF_EVEN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])
By default, While rounding decimal numbers using the decimal module, the numbers are rounded evenly. We can change this behavior by changing the “rounding” value in the context as follows.
import decimal
decimal.getcontext().rounding="ROUND_HALF_DOWN"
print(decimal.getcontext())
Output:
Context(prec=3, rounding=ROUND_HALF_DOWN, Emin=-999999, Emax=999999, capitals=1, clamp=0, flags=[Inexact, Rounded], traps=[InvalidOperation, DivisionByZero, Overflow])
All the arithmetic operations on decimal numbers defined by decimal module are similar to that of the floating point numbers. The difference lies in precision of the values due to difference in implementation.
Rounding values
We can round the numbers to certain digits using the round() function. The round function takes the decimal number to be rounded as first argument and number of digits to which it should be rounded as second argument and returns the rounded decimal value as follows.
import decimal
num1=decimal.Decimal(4)
num2=decimal.Decimal(3)
print("First number is:",num1)
print("Second number is:",num2)
num3=num1/num2
print("num1 divided by num2 is:",num3)
num4=round(num3,2)
print("Rounded value upto two decimal points is:",num4)
Output:
First number is: 4
Second number is: 3
num1 divided by num2 is: 1.333333333333333333333333333
Rounded value upto two decimal points is: 1.33
Comparing numbers using decimal module
As seen in one of the above sections, comparing floating point numbers can lead to incorrect results but decimal numbers are precise and their comparison will always get the intended result. This can be seen as follows.
import decimal
x=decimal.Decimal("1.2")
y=decimal.Decimal("2.2")
z=decimal.Decimal("3.4")
a=x+y
print("x:",x)
print("y:",y)
print("z:",z)
print("x+y:",a)
print("x+y==z?:",a==z)
Output:
x: 1.2
y: 2.2
z: 3.4
x+y: 3.4
x+y==z?: True
In the code above, you can see that we have converted strings to decimals instead of converting floating point numbers to decimal. This is done because if we convert a floating point number to decimal, the approximation error is propagated to the decimal number and we will not get the desired output.
Conclusion
In this article, we have studied the drawbacks of doing arithmetic operations with floating point numbers and have used the decimal module to implement the same operations without errors in python.We can also write the programs used in this article with exception handling using python try except to make the programs more robust and handle errors in a systematic way. Stay tuned for more informative articles.
Recommended Python Training
Course: Python 3 For Beginners
Over 15 hours of video content with guided instruction for beginners. Learn how to create real world applications and master the basics.