我在Python中使用Decimal库,并使用打印出值
format(value, 'f')
,其中值为Decimal
。我得到10.00000
形式的数字,它反映了小数的精度。我知道float
支持is_integer
,但似乎缺少类似的小数位API。我想知道是否有办法解决这个问题。
答案 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) == val
或val == 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
可以具有任意精度,因此您不应将其转换为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 :(得分: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