显然,浮点数比较总是棘手的。我的(科学)代码中有很多断言检查,因此我经常需要检查总和是否等于1,以及类似的问题。
有没有一种快速简便/最佳实践的方法来执行这些检查?
我能想到的最简单的方法是构建一个定值容差的浮点比较自定义函数,但这对我来说似乎相当丑陋。我希望有一个内置的解决方案,或者至少是极其清晰和直观易懂的东西。
显然,浮点数比较总是棘手的。我的(科学)代码中有很多断言检查,因此我经常需要检查总和是否等于1,以及类似的问题。
有没有一种快速简便/最佳实践的方法来执行这些检查?
我能想到的最简单的方法是构建一个定值容差的浮点比较自定义函数,但这对我来说似乎相当丑陋。我希望有一个内置的解决方案,或者至少是极其清晰和直观易懂的东西。
我认为最有可能的情况是你需要自己编写一个函数。就像我经常用三个东西来运行计算向量测试一样:
最大绝对误差
return max(abs(result(:) - expected(:))) < tolerance
这会逐点计算最大绝对误差并告诉您是否小于某个容忍度。
最大过量误差计数
return sum( (abs(result(:) - expected(:))) < tolerance )
这将返回落在你容忍范围外的点数。也很容易修改以返回百分比。
均方根误差
return norm(result(:) - expected(:)) < rmsTolerance
由于存在许多比较浮点数数组的标准,我建议编写一个函数,该函数接受计算结果、期望结果、容差和比较方法。这样,您可以使检查非常紧凑,而且比尝试在注释中解释自己所做的事情要好得多。
如果输入非常大或非常小的数字,任何固定公差都会失败,最简单的解决方案是使用eps
来获得双精度:
任何固定公差都会失败,如果你输入非常大或非常小的数字,最简单的解决方案是使用eps
来获得双精度:
abs(A-B)<eps(A)*4
4是完全任意的数字,在大多数情况下足够使用。
我不知道有任何特殊的内置解决方案。也许可以使用eps函数来实现?
例如,正如您可能知道的那样,以下代码将返回False(即0
):
>> 0.1 + 0.1 + 0.1 == 0.3
ans =
0
>> (0.1+0.1+0.1) - 0.3 < eps
ans =
1
eps
,因为 eps(10000)
比默认值 eps(1)
大。 - Jonas我对xUnit有着良好的使用经验,它是Matlab的一个单元测试框架。安装后,您可以使用以下功能:
assertVectorsAlmostEqual(a,b)
(检查向量之间的范数接近程度;可配置绝对/相对容差和合理的默认值)assertElementsAlmostEqual(a,b)
(同样的检查,但是逐个元素地进行比较--因此[1 1e-12]
和[1 -1e-9]
将与前者相等,但与后者不相等)。它们经过了充分的测试,使用起来很快且易于阅读。函数名称相当长,但是使用任何像样的编辑器(或Matlab自带的编辑器),您都可以将它们写成assertV<tab>
。
对于那些了解MATLAB和Python(NumPy)的人来说,检查以下Python函数的代码可能会很有用,它们可以完成这项工作:
numpy.allclose(a, b, rtol=1e-05, atol=1e-08)
numpy.isclose(a, b, rtol=1e-05, atol=1e-08, equal_nan=False)
numpy
。请仔细阅读问题标题和标签。此外,对于那些不熟悉Python和numpy
的人来说,这可能并不具有建设性,因此检查这些实现相当无用。 - rayryengnumpy
代码翻译成 MATLAB,那么这是一个非常有用的答案,我会倾向于点赞。这样,您不仅指出了 numpy
已经具备的功能,还为我们提供了在 MATLAB 中执行此操作的方法。 - rayryeng
eps
来作为容差值是个不错的主意。另外,R2013a及以后版本的单元测试框架中有assertEqual
语句可以帮助检查。 - Jonas