Python:在一般情况下,a可以舍入到b
作为我编写的一些单元测试代码的一部分,我编写了以下函数。 其目的在于确定'a'是否可以舍入为'b',无论“a”或“b”的准确程度如何。
def couldRoundTo(a,b):
"""Can you round a to some number of digits, such that it equals b?"""
roundEnd = len(str(b))
if a == b:
return True
for x in range(0,roundEnd):
if round(a,x) == b:
return True
return False
以下是该函数的一些输出:
>>> couldRoundTo(3.934567892987, 3.9)
True
>>> couldRoundTo(3.934567892987, 3.3)
False
>>> couldRoundTo(3.934567892987, 3.93)
True
>>> couldRoundTo(3.934567892987, 3.94)
False
据我所知,它可以工作。 不过,考虑到我对浮点精度问题没有完全掌握,我很害怕依赖它。 有人能告诉我这是否是实现此功能的适当方式? 如果不是,我怎么能改进它?
有人能告诉我这是否是实现此功能的适当方式?
这取决于。 如果b
不精确地等于通常从小数到二进制浮点转换直接获得的值,那么给定函数的行为会令人惊讶。
例如:
>>> print(0.1, 0.2/2, 0.3/3)
0.1 0.1 0.1
>>> couldRoundTo(0.123, 0.1)
True
>>> couldRoundTo(0.123, 0.2/2)
True
>>> couldRoundTo(0.123, 0.3/3)
False
这是因为0.3 / 3
的计算结果与0.1
和0.2 / 2
(和round(0.123, 1)
)略有不同。
如果不是,我怎么能改进它?
经验法则:如果您的计算以任何方式具体涉及小数位数,则只需使用Decimal
来避免所有有损基数为2的往返操作。
特别是, Decimal
包含一个称为quantize
的帮助quantize
,使这个问题变得轻而易举:
from decimal import Decimal
def roundable(a, b):
a = Decimal(str(a))
b = Decimal(str(b))
return a.quantize(b) == b
一种方法:
def could_round_to(a, b):
(x, y) = map(len, str(b).split('.'))
round_format = "%" + "%d.%df"%(x, y)
return round_format%a == str(b)
首先,我们取x和y的小数点前后的位数。 然后,我们构造一个格式如%x.yf
。 然后,我们提供a
格式字符串。
>>> "%2.2f"%123.1234
'123.12'
>>> "%2.2f"%123.1264
'123.13'
>>> "%3.2f"%000.001
'0.00'
现在,剩下的就是比较字符串。
我担心的唯一问题是在解释浮点文字时从字符串转换为浮点(如http://docs.python.org/reference/lexical_analysis.html#floating-point-literals中所述)。 我不知道是否有任何保证,浮点文字将评估为最接近给定字符串的浮点数。 这个提到的部分是我希望得到这种保证的规范中的地方。
例如,Java对字符串文字的期望更具体。 从Double.valueOf(String)的文档:
[[]] [参数]被认为是通常的“计算机化的科学记数法”中的精确十进制值或十进制精确值; 这个确切的数值然后在概念上被转换成一个“无限精确”的二进制值,然后通过IEEE 754浮点算术常用的舍入到最近的规则进行舍入,
除非你可以在Python文档的任何地方找到这样的保证,否则你可能会很幸运,因为一些较早的浮点库(Python可能依赖它)将字符串转换为附近的浮点数,而不是最佳可用。
不幸的是,在我看来,无论是round
还是float
,还是浮点规范都不会给你任何有用的保证。
上一篇: Python: a could be rounded to b in the general case
下一篇: How to access a data structure from a currently running Python process on Linux?