Search code examples
python-3.xdecimalfractions

python Decimal.as_integer_ratio() output


Learning Decimal in the standard library, this seems to be a new function in python 3.6:

as_integer_ratio() Return a pair (n, d) of integers that represent the given Decimal instance as a fraction, in lowest terms and with a positive denominator

So I tried it:

print(Decimal(1.25).as_integer_ratio())  # >>> (5, 4)
print(Decimal(1.33).as_integer_ratio())  # >>> (748723438050345, 562949953421312)

Works fine for 1.25, but it is very hard to believe that 748723438050345 / 562949953421312 is the lowest term of fraction for 1.33, maybe 133/100 could be the better output?

OK, I got answered on using Decimal('1.33') other than Decimal(1.33), so does that mean it is preferred to input str other than float when using Decimal()?


Solution

  • Try using

    from decimal import Decimal
    print(Decimal('1.25').as_integer_ratio())  # >>> (5, 4)
    print(Decimal('1.33').as_integer_ratio())
    
    (5, 4)
    (133, 100)
    

    Its difference of the standard

    when you do this

    Decimal(1.25)
    

    Python converts our literal base 10 representations into internal base 2 representations within the float objects. Neither of the values we have chosen can be represented exactly in base 2, so some rounding occurs. These rounded float values are then passed to the decimal constructor and used to construct the internal base 10 representations, which will be used for the computation. Finally, the operation is performed on the decimal objects. So although the decimal constructor supports conversion from float, you should always specify fractional decimal literals as strings to avoid the creation of an inexact intermediate base 2 float object

    To prevent such accident please set

    To avoid inadvertently constructing decimal objects from floats, we can modify the signal handling in the decimal module. We do this by setting to true the value associated with the float operation key in the traps attribute of the decimal module context. With this change in place, our attempt to construct decimal objects directly from floats raises a FloatOperation exception.

    decimal.getcontext().traps[decimal.FloatOperation] = True
    

    For example for below cases exception will be raised

    Decimal(0.8) > 0.7
    

    To answer your question

    Decimal(1.33), so does that mean it is preferred to input str other than float when using Decimal()

    Python float type can result in problems with even the simplest of decimal values, which would be unacceptable in any application where exact arithmetic is needed such as in a financial setting. The Decimal type is a fast correctly rounded number type for performing arithmetic in base 10. Crucially, the decimal type is still a floating point type, albeit with a base of 10 rather than 2 and has finite precision, although user configurable rather than fixed. Using decimal in place of float for say an accounting application can lead to significantly fewer hard to debug edge cases. Decimal package was created to remove that deficiency of float.