How to convert a decimal number into fraction?

前端 未结 4 660
夕颜
夕颜 2020-11-28 04:35

I was wondering how to convert a decimal into a fraction in its lowest form in Python.

For example:

0.25  -> 1/4
0.5   -> 1/2
1.25  -> 5/4
3         


        
相关标签:
4条回答
  • 2020-11-28 04:50

    To expand upon Martijn Pieters excellent answer with an additional option due to the imprecision inherent with more complex floats. For example:

    >>> f = 0.8857097
    >>> f.as_integer_ratio()
    (1994440937439217, 2251799813685248)          # mathematically wrong
    >>> Fraction(f)
    Fraction(1994440937439217, 2251799813685248)  # same result but in a class
    >>> Fraction(f).limit_denominator()
    Fraction(871913, 984423)                      # still imprecise
    

    The mathematical result desired was 8857097/10000000 which can be achieved by casting to a string and then manipulating it.

    Edited Response

    I found a much simpler way to resolve the accuracy issue.

    >>> Fraction(str(f))
    Fraction(8857097, 10000000)
    

    Casting as to a string also allows for accurate Decimal instances

    >>> Decimal(f).as_integer_ratio()
    (1994440937439217, 2251799813685248)
    >>> Decimal(str(f)).as_integer_ratio()
    (8857097, 10000000)
    

    Original Response

    def float_to_ratio(flt):
        if int(flt) == flt:        # to prevent 3.0 -> 30/10
            return int(flt), 1
        flt_str = str(flt)
        flt_split = flt_str.split('.')
        numerator = int(''.join(flt_split))
        denominator = 10 ** len(flt_split[1])
        return numerator, denominator
    

    Now let's test it:

    >>> float_to_ratio(f)
    (8857097, 10000000)      # mathematically correct
    

    I will note that this kind of fraction precision is not optimized and will usually not be needed, but for completeness it is here. This function doesn't simplify the fraction, but you can do additional processing to reduce it:

    >>> n = 0.5
    >>> float_to_ratio(n)
    (5, 10)
    >>> Fraction(*float_to_ratio(n))
    Fraction(1, 2)
    
    0 讨论(0)
  • 2020-11-28 05:01

    If you'd like to print a proper fraction, this little recipe should do:

    from fractions import Fraction    
    
    def dec_to_proper_frac(dec):
        sign = "-" if dec < 0 else ""
        frac = Fraction(abs(dec))
        return (f"{sign}{frac.numerator // frac.denominator} "
                f"{frac.numerator % frac.denominator}/{frac.denominator}")
    

    This will print as follows:

    >>> dec_to_proper_frac(3.75)
    >>> "3 3/4"
    
    0 讨论(0)
  • 2020-11-28 05:06
    from fractions import Fraction
    
    print(Fraction(0.25))
    print(Fraction(0.5))
    print(Fraction(1.25))
    print(Fraction(3))
    
    #1/4
    #1/2
    #5/4
    #3
    
    0 讨论(0)
  • 2020-11-28 05:13

    You have two options:

    1. Use float.as_integer_ratio():

      >>> (0.25).as_integer_ratio()
      (1, 4)
      

      (as of Python 3.6, you can do the same with a decimal.Decimal() object.)

    2. Use the fractions.Fraction() type:

      >>> from fractions import Fraction
      >>> Fraction(0.25)
      Fraction(1, 4)
      

    The latter has a very helpful str() conversion:

    >>> str(Fraction(0.25))
    '1/4'
    >>> print Fraction(0.25)
    1/4
    

    Because floating point values can be imprecise, you can end up with 'weird' fractions; limit the denominator to 'simplify' the fraction somewhat, with Fraction.limit_denominator():

    >>> Fraction(0.185)
    Fraction(3332663724254167, 18014398509481984)
    >>> Fraction(0.185).limit_denominator()
    Fraction(37, 200)
    

    If you are using Python 2.6 still, then Fraction() doesn't yet support passing in a float directly, but you can combine the two techniques above into:

    Fraction(*0.25.as_integer_ratio())
    

    Or you can just use the Fraction.from_float() class method:

    Fraction.from_float(0.25)
    

    which essentially does the same thing, e.g. take the integer ratio tuple and pass that in as two separate arguments.

    And a small demo with your sample values:

    >>> for f in (0.25, 0.5, 1.25, 3.0):
    ...     print f.as_integer_ratio()
    ...     print repr(Fraction(f)), Fraction(f)
    ... 
    (1, 4)
    Fraction(1, 4) 1/4
    (1, 2)
    Fraction(1, 2) 1/2
    (5, 4)
    Fraction(5, 4) 5/4
    (3, 1)
    Fraction(3, 1) 3
    

    Both the fractions module and the float.as_integer_ratio() method are new in Python 2.6.

    0 讨论(0)
提交回复
热议问题