Java中复杂对象的不精确比较?

时间:2014-07-13 13:34:46

标签: java comparison double epsilon

众所周知,如果不精确地比较double值,则具有明确的精度(epsilon)。例如,出于这个原因,jUnit已弃用双参数assertEquals(double,double)

但是,如果我们有一个复合类,如Matrix或Vector,那该怎么办?如何建议对它进行比较?标准equals()只需要精确比较。关于这个有什么约定吗?

3 个答案:

答案 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来对任何特定情况进行相关比较,而不是在课程中嵌入比较标准。