我在 Python 中使用 Decimal 库,并使用 打印出值
format(value, 'f')
,其中 value 是 a Decimal
。我得到表格中的数字10.00000
,它反映了小数点的精度。我知道float
支持is_integer
,但似乎缺乏类似的小数 API。我想知道是否有办法解决这个问题。
8 回答
您可以使用模运算来检查是否存在非整数余数:
>>> from decimal import Decimal
>>> Decimal('3.14') % 1 == 0
False
>>> Decimal('3') % 1 == 0
True
>>> Decimal('3.0') % 1 == 0
True
尝试math.floor(val) == val
或val == int(val)
。
数学解决方案是将您的十进制数转换为整数,然后测试它与您的数字是否相等。
由于Decimal
可以具有任意精度,因此不应将其转换为int
or 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
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 对值进行测试。
从 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
您可以调用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
在上面所说的基础上,我使用了:
>>> not 2.5 % 1
False
>>> not 1.0 % 1
True
>>> not 14.000001 % 1
False
>>> not 2.00000000 % 1
True
因此,您可以使用以下一种衬里:
return not value % 1
它将为您提供所需的布尔值。
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