Python fraction and decimal

The Python Fraction and Decimal provide us a way to represent a fractional value.In this post we will see how to use them in our program.Let us first discuss Fraction and then we will discuss Decimal.


With Fraction any number is represented in the form of numerator and denominator in their lowest form.Say for instance a number 4.25 can be obtained by dividing 17 by 4.Hence when we pass 4.25 to Fraction is gives the number 17 and 4.Consider the code example below.

>>> from fractions import Fraction #this line is necessary
>>> Fraction(4.25)
Fraction(17 , 4)

The number 17 is the numerator and 4 being the denominator.

Note you can also pass the numerator and denominator,in such case Fraction will reduce them to it’s lowest form. Here are some more examples.

>>> from fractions import Fraction #this line is necessary
>>> Fraction(12.5)
Fraction(25, 2)
>>> Fraction( 18 , 3)
Fraction(6, 1)
>>> Fraction( -19 , 5)
>>> Fraction(-19, 5)
>>> Fraction()
Fraction(0, 1)
>>> Fraction(20)
Fraction(20, 1)

You can also perform any of the mathematical operation with Fraction.

>>> from fractions import Fraction #this line is necessary
>>> Fraction(23 , 2) + Fraction(23 , 2) #(23/2+23/2)=(46/2)=23/1
Fraction(23, 1)
>>> Fraction( 90 , 45) - Fraction(2) #(90/45-2)=(2-2)=0 or 0/1
Fraction(0, 1)

Fraction still suffers from some disadvantage such as look at the code below.

>>> Fraction(0.1)* Fraction(3) - Fraction(0.3) #0.1*3 - 0.3=0 or 0/1
Fraction(1, 36028797018963968) #expect Fraction(0 , 1)
>>> Fraction(0.1) 
Fraction(3602879701896397, 36028797018963968) #expected Fraction(1 , 10)

We expect the output to be ‘Fraction(0,1)’ for the first one but it is not this is because Fraction still takes into consideration the binary format of the Floating point value which is cause by the shortcoming of IEEE 754 format.The incorrect result in the second output is also caused by the same reason.

String digits

To counteract the above issue instead of writing the number in Fraction as a real number we will write it as a string of digits meaning instead of writing 0.1 we will write it as ‘0.1’.Now look at the code example below.

>>> from fractions import Fraction #this line is necessary
>>> Fraction('0.1')* Fraction(3) - Fraction('0.3')
Fraction(0, 1)
>>> Fraction('0.1')
Fraction(1, 10)

Now everything is as expected


Decimal are much more easier to implement than Fraction,unlike Fraction which represent every number in a numerator and denominator format Decimal represent the number in it’s normal way.To use Decimal the Capital letter ‘D’ is used and the number is represented inside a bracket next to ‘D’.

>>> from decimal import Decimal as D #this is neccesary
>>> D(0.2123)
Decimal('0.212299999999999988720134069808409549295902252197265625') #unexpected 
>>> D(12.3)
Decimal('12.300000000000000710542735760100185871124267578125') ##unexpected

The long digit output that you see is due to the binary floating point format lossless conversion.Such process does not render a correct output,to avoid it write the number in a string format.

>>> from decimal import Decimal as D #this is neccesary
>>> D('0.2123')
>>> D('12.3')

Another example is given below.

>>> from decimal import Decimal as D #this is neccesary
>>> D(0.1)* D(3) - D(0.3)
Decimal('2.775557561565156540423631668E-17') #expected Decimal(0)
>>> D('0.1')* D(3) - D('0.3')
Decimal('0.0') #correct!!

After changing the number to string format everything renders correctly.

Subscribe here:

Some difference between arithmetic operation on integers and Decimal object

i)Calculating remainder

In integer performing division will render the sign similar to the divisor by with Decimal object the sign is similar to the dividend.

>>> from decimal import Decimal as D #this is neccesary
>>> (-23) % 5
>>> D(-23) % 5

ii)Calculating division

While calculating division with integer the value is always rounded away from the zero,but in case of Decimal object the value is rounded towards the zero.

>>> from decimal import Decimal as D #this is neccesary
>>> -5//4 #output is -1.25
>>> D(-5)//D(4)

Note the behavior is only exhibited when either divisor or dividend is a negative value otherwise everything is process normally.

>>> from decimal import Decimal as D #this is neccesary
>>> 5//4 
>>> D(5)//D(4)
>>> D(-5)//D(-4)