30

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

4

8 回答 8

46

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

>>> from decimal import Decimal
>>> Decimal('3.14') % 1 == 0
False
>>> Decimal('3') % 1 == 0
True
>>> Decimal('3.0') % 1 == 0
True
于 2013-11-13T21:48:54.563 回答
9

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

于 2013-11-13T21:51:13.763 回答
7

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

由于Decimal可以具有任意精度,因此不应将其转换为intor 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

于 2013-11-13T22:18:08.507 回答
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

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

于 2013-11-13T21:53:06.653 回答
3

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

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

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

>>> from decimal import Decimal
>>> Decimal("123.456").as_integer_ratio()[1] == 1
False
>>> Decimal("123.000").as_integer_ratio()[1] == 1
True
于 2021-06-04T22:20:59.230 回答
1

您可以调用as_tuple()Decimal 对象来获取一起定义 Decimal 值的符号数字序列和指数。

如果归一化 Decimal 的指数为非负数,则您的值没有小数部分,即它是整数。所以你可以很容易地检查这个:

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
于 2020-02-14T11:03:22.110 回答
1

在上面所说的基础上,我使用了:

>>> not 2.5 % 1
False
>>> not 1.0 % 1
True
>>> not 14.000001 % 1
False
>>> not 2.00000000 % 1
True

因此,您可以使用以下一种衬里:

return not value % 1

它将为您提供所需的布尔值。

于 2022-01-11T12:45:24.713 回答
0

Decimal 类具有to_integral_exact将十进制转换为整数的功能,并且还会发出信号,如果有任何非零数字被丢弃。 https://docs.python.org/3/library/decimal.html#decimal.Decimal.to_integral_exact

使用这些信息,我们也可以is_integer为 Decimal 实现浮点数:

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
于 2020-12-10T05:45:37.167 回答