Search code examples
pythonfloating-pointfractions

Significant Reason behind Fraction(0.1) = 3602879701896397/36028797018963968


I was looking at the Python documentation of fractions and trying this code:

from fractions import Fraction

>>> print("Fraction (0.5):", Fraction(0.5))
Fraction (0.5): 1/2
>>> print("Fraction (0.1):", Fraction(0.1)) 
Fraction (0.1): 3602879701896397/36028797018963968
>>> print(1/10) 
0.1

Looking at the Fraction(0.1) result I thought it was my computer problem, but when I tried it on several computers the results were same.

My question

  1. is there any computational reason to choose these odd numbers 3602879701896397/36028797018963968 instead of 1/10 just like 1/2 as it chosen for Fraction(0.5).
  2. more of these exist in python?

Solution

  • Yes, that's because that's the integer ration for the float 0.1 (which can't be represented exactly with floats):

    >>> (0.1).as_integer_ratio()
    (3602879701896397, 36028797018963968)
    
    >>> '{:.30f}'.format(0.1)   # just to show that it can't be represented exactly I print 30 digits of 0.1
    '0.100000000000000005551115123126'
    

    If you want correct Fractions you need to use both arguments or pass in a string:

    >>> Fraction(1, 10)
    Fraction(1, 10)
    
    >>> Fraction('0.1')
    Fraction(1, 10)
    

    Or limit the denominator after creating it from a float (not guaranteed to work in all cases):

    >>> Fraction(0.1).limit_denominator()
    Fraction(1, 10)
    

    As for your second question: There are infinitely many rational numbers (decimal numbers that could be represented exactly as Fraction) in math but a computer uses 64bits for doubles (the Python float type). That means only a few real numbers can have an exact representation as double. So there are a lot of other numbers with the same problem, just to name a few:

    >>> Fraction(0.2)
    Fraction(3602879701896397, 18014398509481984)
    
    >>> Fraction(0.3)
    Fraction(5404319552844595, 18014398509481984)
    
    >>> Fraction(1/3)
    Fraction(6004799503160661, 18014398509481984)