众所周知,double
如果使用显式精度(epsilon)不精确地比较,值会更好。例如,assertEquals(double,double)
由于这个原因,不推荐使用两个参数jUnit
。
但是如果我们有一个复合类,比如 Matrix 或 Vector。建议如何对其进行比较?标准equals()
只希望进行精确的比较。对此有什么约定吗?
众所周知,double
如果使用显式精度(epsilon)不精确地比较,值会更好。例如,assertEquals(double,double)
由于这个原因,不推荐使用两个参数jUnit
。
但是如果我们有一个复合类,比如 Matrix 或 Vector。建议如何对其进行比较?标准equals()
只希望进行精确的比较。对此有什么约定吗?
A good question, and one without some standard answer (AFAIK), as the problem is not trivial.
First of all, you should read Bruce Dawson's excellent article Comparing Floating Point Numbers, 2012 Edition to get an insight into this surprisingly complex problem. The worst error you can make is to use the infamous abs(a - b) < eps
-- don't, it only works for a very limited range of floats and quickly leads to strange bugs! The second-worst error is that you only provide fixed eps
values, as the specific values depends very much on your application.
Once you understood the basic problems of float comparisons, the simplest algorithm for a vector comparison would be define two vectors as approximatively equal of each of their corresponding components are approximatively equal (and don't forget to compare the dimensions if they can be different!). However, a better approach would be to check whether the length of the difference vector is approximatively zero.
For matrices, its similar -- consider two matrices approximatively equal if all their corresponding components are approximatively equal. The analogy to the second vector algorithm (difference vector length) could be to check whether the difference matrix determinant is approximatively zero, but this is just a wild hobby-mathematician's guess.
In any case, you should not use a single eps
for the approximate comparisons, but let the user specify it, because no eps
is good for all applications, regardless of your approximate comparison algorithm. And again: Never use absolute error for approximate float comparisons!
Conventionally the equals()
method is used to determine if two objects are "equal" as in by the properties of mathematical equality (such as passing the reflexive property and such). If you are using matrices and/or vectors that contain doubles then it is likely that it will be hard to tell whether or not 2 matrices or 2 vectors are reflexive. In this case it might be better to create a method isSimilar()
or isAproximatlyEqual()
(personally I like the second one because there is no confusion with geometric similarity). By doing this you can allow for a margin of error of some x when comparing 2 doubles and still keep the equals()
method for conventional equality. And if you really want to get fancy you can add margin of error as a parameter for these methods.
`
boolean isAproximatlyEqual(double d1, double d2) {
isAproximatlyEqual(d1, d2, 0.001);
}
boolean isAproximatlyEqual(double d1, double d2, double margin) {
abs(d1 - d2) < margin;
}
`
比较此类对象的最佳方法可能因情况而异。这就是我们有Comparator
接口的原因。Comparator
您可以编写 a来针对任何给定情况进行相关比较,而不是将比较标准嵌入到类中。