Я использую библиотеку Decimal в Python и печатаю значения, используя
format(value, 'f')
, где значение равно Decimal
. Я получаю числа в форме 10.00000
, которая отражает точность десятичного числа. Я знаю, что float
поддерживает is_integer
, но, похоже, отсутствует аналогичный API для десятичных знаков. Мне было интересно, есть ли способ обойти это.
Python Decimal - проверка, если целое число
Ответ 1
Вы можете использовать операцию modulo для проверки наличия нецелого остатка:
>>> from decimal import Decimal
>>> Decimal('3.14') % 1 == 0
False
>>> Decimal('3') % 1 == 0
True
>>> Decimal('3.0') % 1 == 0
True
Ответ 2
Попробуйте math.floor(val) == val
или val == int(val)
.
Ответ 3
Математическое решение состоит в том, чтобы преобразовать ваше десятичное число в целое, а затем проверить его равенство с вашим числом.
Поскольку Decimal
может иметь произвольную точность, вы не должны преобразовывать ее в int
или float
.
К счастью, у класса Decimal
есть значение to_integral_value
которое выполняет преобразование для вас. Вы можете принять решение как это:
def is_integer(d):
return d == d.to_integral_value()
Пример:
from decimal import Decimal
d_int = Decimal(3)
assert is_integer(d_int)
d_float = Decimal(3.1415)
assert not is_integer(d_float)
Смотрите: http://docs.python.org/2/library/decimal.html#decimal.Decimal.to_integral_value
Ответ 4
Десятичный имеет метод "скрытый", называемый _isinteger(), который работает подобно методу float is_integer():
>>> 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
Как вы можете видеть, вам придется поймать исключение. В качестве альтернативы вы можете выполнить тест по значению ПЕРЕД тем, как вы передадите его в Decimal, используя метод float, как вы упомянули, или используя isinstance.
Ответ 5
Другой способ:
>>> float(Decimal('3.14')).is_integer()
False
>>> float(Decimal('3.0')).is_integer()
True
Также возможно использование так называемого "магического метода" (или двойного подчеркивания) __float__()
:
>>> Decimal('3.14').__float__().is_integer()
False
>>> Decimal('3.0').__float__().is_integer()
True
Тесты производительности
Истекшее время за 10 ^ 6 итераций:
0.462s | d == d.to_integral_value()
0.527s | d % 1 == 0
0.998s | d == int(d)
1.023s | float(d).is_integer()
Тестовый код:
from time import perf_counter as perf
from decimal import Decimal
l = list(map(Decimal, range(1000000)))
t = perf()
all(d == d.to_integral_value() for d in l)
print(f'{perf()-t:.3f}s', '| d == d.to_integral_value()')
t = perf()
all(d % 1 == 0 for d in l)
print(f'{perf()-t:.3f}s', '| d % 1 == 0')
t = perf()
all(d == int(d) for d in l)
print(f'{perf()-t:.3f}s', '| d == int(d)')
t = perf()
all(float(d).is_integer() for d in l)
print(f'{perf()-t:.3f}s', '| float(d).is_integer()')