众所周知,如果不精确地比较double
值,则具有明确的精度(epsilon)。例如,出于这个原因,jUnit
已弃用双参数assertEquals(double,double)
。
但是,如果我们有一个复合类,如Matrix或Vector,那该怎么办?如何建议对它进行比较?标准equals()
只需要精确比较。关于这个有什么约定吗?
答案 0 :(得分:1)
一个很好的问题,一个没有标准答案的答案(AFAIK),因为问题并非无足轻重。
首先,您应该阅读Bruce Dawson的优秀文章Comparing Floating Point Numbers, 2012 Edition,以深入了解这个令人惊讶的复杂问题。您可以犯的最大错误是使用臭名昭着的abs(a - b) < eps
- 不要,它只适用于非常有限的浮动范围,很快就会导致奇怪的错误!第二个最差的错误是您只提供固定的eps
值,因为具体值很大程度上取决于您的应用程序。
一旦你理解了浮点比较的基本问题,用于矢量比较的最简单的算法就是定义两个矢量,因为它们的相应组件的近似相等,近似相等(如果它们可以,则不要忘记比较尺寸与众不同!)然而,更好的方法是检查差矢量的长度是否近似为零。
对于矩阵,它是相似的 - 如果所有相应的分量都近似相等,则认为两个矩阵近似相等。与第二矢量算法(差矢量长度)的类比可以是检查差矩阵行列式是否近似为零,但这只是一个狂野的爱好 - 数学家的猜测。
在任何情况下,您都不应该使用单个eps
进行近似比较,而是让用户指定它,因为没有eps
适用于所有应用程序,无论您的近似比较算法如何。再次:永远不要使用绝对误差进行近似浮点数比较!
答案 1 :(得分:0)
传统上,equals()
方法用于确定两个对象是否相等&#34;因为数学相等的属性(例如传递反身属性等)。如果您正在使用包含双精度的矩阵和/或向量,那么很可能很难判断2个矩阵或2个向量是否具有自反性。在这种情况下,创建方法isSimilar()
或isAproximatlyEqual()
可能更好(我个人喜欢第二个方法,因为几何相似性没有混淆)。通过这样做,您可以在比较2个双精度时允许某些x的误差范围,并且仍然保持equals()
方法用于传统的相等。如果你真的想要获得幻想,你可以添加误差范围作为这些方法的参数。
`
boolean isAproximatlyEqual(double d1, double d2) {
isAproximatlyEqual(d1, d2, 0.001);
}
boolean isAproximatlyEqual(double d1, double d2, double margin) {
abs(d1 - d2) < margin;
}
`
答案 2 :(得分:0)
比较这些对象的最佳方式可能因情况而异。这就是我们拥有Comparator
界面的原因。您可以编写Comparator
来对任何特定情况进行相关比较,而不是在课程中嵌入比较标准。