Gor*_*ley 291 python floating-point
众所周知,由于舍入和精度问题,比较浮点数是否相等.
例如:https: //randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
在Python中处理这个问题的推荐方法是什么?
当然,这个地方有一个标准的库函数吗?
Mar*_*som 282
Python 3.5添加了PEP 485中描述的math.isclose和cmath.isclose功能.
如果您使用的是早期版本的Python,则文档中会给出等效函数.
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
return abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)
Run Code Online (Sandbox Code Playgroud)
rel_tol是相对容差,它乘以两个参数的大小越大; 随着值越大,它们之间允许的差异也越大,同时仍然认为它们相等.
abs_tol是在所有情况下按原样应用的绝对容差.如果差值小于这些公差中的任何一个,则认为这些值相等.
And*_*ite 66
以下简单的事情不够好吗?
return abs(f1 - f2) <= allowed_error
Run Code Online (Sandbox Code Playgroud)
小智 38
我同意Gareth的答案可能是最适合作为轻量级功能/解决方案.
但我认为如果您使用NumPy或正在考虑它会有所帮助,那么就有一个打包的功能.
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
Run Code Online (Sandbox Code Playgroud)
虽然有点免责声明:根据您的平台,安装NumPy可能是一项非常重要的体验.
Eri*_*hil 12
浮点数无法与平等进行比较的常识是不准确的.浮点数与整数没有什么不同:如果你评估"a == b",如果它们是相同的数字你将得到真,否则你将得到假(理解两个NaN当然不是相同的数字).
实际的问题是这样的:如果我做了一些计算并且不确定我要比较的两个数字是完全正确的,那又怎么样?浮点和整数的问题是相同的.如果计算整数表达式"7/3*3",它将不会等于"7*3/3".
因此,假设我们问"我如何比较整数是否平等?" 在这种情况下.没有一个答案; 你应该做什么取决于具体情况,特别是你有什么样的错误以及你想要达到的目标.
以下是一些可能的选择.
如果您想获得"真实"结果,如果数学上精确的数字相等,那么您可能会尝试使用您执行的计算属性来证明您在两个数字中得到相同的错误.如果这是可行的,并且你比较两个由表达式产生的数字,如果精确计算得到相同的数字,那么你将从比较中得到"真".另一种方法是您可以分析计算的属性并证明误差永远不会超过一定量,可能是绝对量或相对于其中一个输入或其中一个输出的量.在这种情况下,您可以询问两个计算的数字是否至少相差该数量,如果它们在该时间间隔内,则返回"true".如果你无法证明错误的界限,你可能会猜测并希望最好.猜测的一种方法是评估许多随机样本,看看你在结果中得到什么样的分布.
当然,因为如果数学上精确的结果是相等的,我们只设置你得到"真"的要求,我们留下了即使它们不相等也能得到"真"的可能性.(事实上,我们可以通过始终返回"true"来满足要求.这使得计算简单但通常是不合需要的,因此我将讨论改善下面的情况.)
如果你想得到一个"假"结果,如果数学上确切的数字是不相等的,你需要证明如果数学上确切的数字不相等,你对数字的评估会产生不同的数字.在许多常见情况下,这可能不可能用于实际目的.那么让我们考虑另一种选择.
一个有用的要求可能是,如果数学上精确的数字相差超过一定数量,我们会得到"假"结果.例如,也许我们将计算在计算机游戏中投掷的球的位置,我们想知道它是否击中了蝙蝠.在这种情况下,如果球击中球棒,我们当然希望得到"真实",如果球远离击球,我们想要"假",如果击球,我们可以接受错误的"真实"答案一个数学上精确的模拟错过了蝙蝠但是在击打蝙蝠的毫米之内.在这种情况下,我们需要证明(或猜测/估计)我们对球的位置和球棒位置的计算具有至多1毫米的组合误差(对于所有感兴趣的位置).如果球和球棒相距超过一毫米,这将使我们总是返回"假",如果它们接触则返回"真",如果它们足够接近可以接受,则返回"真".
那么,在比较浮点数时,如何决定返回什么,在很大程度上取决于您的具体情况.
至于如何证明计算的误差范围,这可能是一个复杂的主题.在舍入到最接近模式下使用IEEE 754标准的任何浮点实现都会返回最接近任何基本操作(特别是乘法,除法,加法,减法,平方根)的精确结果的浮点数.(如果是平局,那么低位是偶数.)(特别注意平方根和除法;你的语言实现可能会使用那些不符合IEEE 754的方法.)由于这个要求,我们知道单个结果中的错误最多为最低有效位的1/2.(如果更多,则舍入将变为不同的数字,该值在值的1/2之内.)
从那里开始变得更加复杂; 下一步是执行一个操作,其中一个输入已经有一些错误.对于简单表达式,可以通过计算跟踪这些错误以达到最终错误的界限.实际上,这只能在少数几种情况下完成,例如在高质量的数学图书馆工作.当然,您需要精确控制所执行的操作.高级语言通常会给编译器带来很多麻烦,因此您可能不知道执行的操作顺序.
关于这个话题还有很多可以写的,但是我必须停在那里.总之,答案是:没有用于此比较的库例程,因为没有一个解决方案能够满足大多数值得投入库例程的需求.(如果与相对或绝对错误间隔进行比较就足够了,您可以在没有库例程的情况下完成.)
Gar*_*han 11
我不知道实现Dawson AlmostEqual2sComplement功能的Python标准库(或其他地方)中的任何内容.如果这是你想要的那种行为,你必须自己实现它.(在这种情况下,不是使用道森的聪明的按位黑客,你可能会更好地使用更常规的形式if abs(a-b) <= eps1*(abs(a)+abs(b)) + eps2或类似的测试.为了获得类似道森的行为,你可能会说类似于if abs(a-b) <= eps*max(EPS,abs(a),abs(b))一些小的固定EPS;这不完全是和道森一样,但它在精神上是相似的.
math.isclose()已为此添加到 Python 3.5(源代码)。这是它到 Python 2 的一个端口。它与 Mark Ransom 的 one-liner 不同之处在于它可以正确处理“inf”和“-inf”。
def isclose(a, b, rel_tol=1e-09, abs_tol=0.0):
'''
Python 2 implementation of Python 3.5 math.isclose()
https://hg.python.org/cpython/file/tip/Modules/mathmodule.c#l1993
'''
# sanity check on the inputs
if rel_tol < 0 or abs_tol < 0:
raise ValueError("tolerances must be non-negative")
# short circuit exact equality -- needed to catch two infinities of
# the same sign. And perhaps speeds things up a bit sometimes.
if a == b:
return True
# This catches the case of two infinities of opposite sign, or
# one infinity and one finite number. Two infinities of opposite
# sign would otherwise have an infinite relative tolerance.
# Two infinities of the same sign are caught by the equality check
# above.
if math.isinf(a) or math.isinf(b):
return False
# now do the regular computation
# this is essentially the "weak" test from the Boost library
diff = math.fabs(b - a)
result = (((diff <= math.fabs(rel_tol * b)) or
(diff <= math.fabs(rel_tol * a))) or
(diff <= abs_tol))
return result
Run Code Online (Sandbox Code Playgroud)
小智 8
就绝对误差而言,你可以检查一下
if abs(a - b) <= error:
print("Almost equal")
Run Code Online (Sandbox Code Playgroud)
关于为什么 float 在 Python 中表现得很奇怪的一些信息: Python 3 教程 03 - if-else、逻辑运算符和初学者最常犯的错误
您还可以使用math.isclose来计算相对误差。
如果你想在测试/ TDD环境中使用它,我会说这是一种标准方式:
from nose.tools import assert_almost_equals
assert_almost_equals(x, y, places=7) #default is 7
Run Code Online (Sandbox Code Playgroud)
小智 5
这对于您想要确保两个数字“精确度”相同且无需指定容差的情况非常有用:
求两个数的最小精度
将它们都舍入到最小精度并进行比较
def isclose(a, b):
astr = str(a)
aprec = len(astr.split('.')[1]) if '.' in astr else 0
bstr = str(b)
bprec = len(bstr.split('.')[1]) if '.' in bstr else 0
prec = min(aprec, bprec)
return round(a, prec) == round(b, prec)
Run Code Online (Sandbox Code Playgroud)
正如所写,它仅适用于字符串表示中没有“e”的数字(意思是 0.9999999999995e-4 < number <= 0.9999999999995e11)
例子:
>>> isclose(10.0, 10.049)
True
>>> isclose(10.0, 10.05)
False
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
185668 次 |
| 最近记录: |