python十进制 - 检查是否为整数

时间:2013-11-13 21:45:09

标签: python format decimal

我在Python中使用Decimal库,并使用打印出值 format(value, 'f'),其中值为Decimal。我得到10.00000形式的数字,它反映了小数的精度。我知道float支持is_integer,但似乎缺少类似的小数位API。我想知道是否有办法解决这个问题。

8 个答案:

答案 0 :(得分:21)

您可以使用模运算来检查是否存在非整数余数:

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

答案 1 :(得分:4)

尝试math.floor(val) == valval == int(val)

答案 2 :(得分:4)

Decimal确实有一个名为_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

正如您所看到的,您必须捕获异常。或者,您可以使用所提到的浮点方法或使用isinstance将值传递给Decimal之前对值进行测试。

答案 3 :(得分:4)

数学解决方案是将您的十进制数转换为整数,然后用您的数字测试它的相等性。

由于Decimal可以具有任意精度,因此您不应将其转换为intfloat

幸运的是,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 :(得分:1)

您可以在小数对象上调用as_tuple()以获取符号数字的顺序以及指数一起定义十进制值。

如果归一化十进制的指数为非负数,则您的值没有小数部分,即它是整数。因此,您可以非常轻松地进行检查:

def is_integer(dec):
    """True if the given Decimal value is an integer, False otherwise."""
    return dec.normalize().as_tuple()[2] >= 0

尝试一下,看看:

from decimal import Decimal


decimals = [
    Decimal('0'),
    Decimal('0.0000'),
    Decimal('1'),
    Decimal('-1'),
    Decimal('1000000'),
    Decimal('0.1'),
    Decimal('-0.0000000009'),
    Decimal('32.4')]

for d in decimals:
    print("Is {} an integer? {}".format(d, is_integer(d)))
Is 0 an integer? True
Is 0.0000 an integer? True
Is 1 an integer? True
Is -1 an integer? True
Is 1000000 an integer? True
Is 0.1 an integer? False
Is -9E-10 an integer? False
Is 32.4 an integer? False

答案 5 :(得分:0)

最直接,最易读(也是“ pythonic”?)的方式可能是:

>>> 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()')

答案 6 :(得分:0)

十进制类具有函数to_integral_exact,该函数将十进制转换为整数,并发出信号,说明是否丢弃了任何非零数字。 https://docs.python.org/3/library/decimal.html#decimal.Decimal.to_integral_exact

使用此信息,我们也可以将float的is_integer应用于十进制:

import decimal
def is_integer(value: decimal.Decimal) -> bool:
   is_it = True
   context = decimal.getcontext()
   context.clear_flags()
   exact = value.to_integral_exact()
   if context.flags[decimal.Inexact]:
     is_it = False
   context.clear_flags()
   return is_it

使用以上功能:

# tested on Python 3.9
>>> is_integer(decimal.Decimal("0.23"))
False
>>> is_integer(decimal.Decimal("5.0000"))
True
>>> is_integer(decimal.Decimal("5.0001"))
False

答案 7 :(得分:0)

从 python 3.6 开始,Decimal 有一个方法 as_integer_ratio()

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

as_integer_ratio() 返回一个 (numerator, denominator) 元组。如果分母为 1,则值为整数。

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