python Decimal - checking if integer

I am using the Decimal library in Python, and printing out the values using format(value, 'f'), where value is a Decimal. I get numbers in the form 10.00000, which reflects the precision on the decimal. I know that float supports is_integer, but there seems to be a lack of a similar API for decimals. I was wondering if there was a way around this.


Solution 1:

You could use the modulo operation to check if there is a non-integer remainder:

>>> from decimal import Decimal
>>> Decimal('3.14') % 1 == 0
False
>>> Decimal('3') % 1 == 0
True
>>> Decimal('3.0') % 1 == 0
True

Solution 2:

Try math.floor(val) == val or val == int(val).

Solution 3:

The mathematical solution is to convert your decimal number to integer and then test its equality with your number.

Since Decimal can have an arbitrary precision, you should not convert it to int or float.

Fortunately, the Decimalclass has a to_integral_value which make the conversion for you. You can adopt a solution like this:

def is_integer(d):
    return d == d.to_integral_value()

Example:

from decimal import Decimal

d_int = Decimal(3)
assert is_integer(d_int)

d_float = Decimal(3.1415)
assert not is_integer(d_float)

See: http://docs.python.org/2/library/decimal.html#decimal.Decimal.to_integral_value

Solution 4:

Decimal does have a "hidden" method called _isinteger() that works kind of the like the float's is_integer() method:

>>> Decimal(1)._isinteger()
True
>>> Decimal(1.1)._isinteger()
Traceback (most recent call last):
  File "C:\Program Files (x86)\Wing IDE 4.1\src\debug\tserver\_sandbox.py", line 1, in <module>
    # Used internally for debug sandbox under external interpreter
  File "C:\Python26\Lib\decimal.py", line 649, in __new__
    "First convert the float to a string")
TypeError: Cannot convert float to Decimal.  First convert the float to a string

As you can see, you would have to catch an exception though. Alternatively, you could do the test on the value BEFORE you pass it to Decimal using the float's method as you mentioned or by using isinstance.

Solution 5:

As of python 3.6, Decimal has a method as_integer_ratio().

https://docs.python.org/3/library/decimal.html#decimal.Decimal.as_integer_ratio

as_integer_ratio() returns a (numerator, denominator) tuple. If the denominator is 1, then the value is an integer.

>>> from decimal import Decimal
>>> Decimal("123.456").as_integer_ratio()[1] == 1
False
>>> Decimal("123.000").as_integer_ratio()[1] == 1
True