Mar*_*mes 2 java floating-point double equals instance-variables
我正在重写对象的相等方法。假设里程表的km变量存储为双精度(以及其他一些对于示例不重要的变量)。
public class Odometer {
private double km;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(km);
result = prime * result + (int) (temp ^ (temp >>> 32));
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Odometer other = (Odometer) obj;
if (Double.doubleToLongBits(km) != Double.doubleToLongBits(other.km))
return false;
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,由Eclipse生成的double变量的比较(以及哈希码)是精确的按位比较。但是,有人告诉我在比较float或double值时使用“ epsilon”差异。我什至听说它的短语是“比较浮点数时不要使用相等性”。
boolean equals(double x, double y, double epsilon) {
return x - y < epsilon;
}
Run Code Online (Sandbox Code Playgroud)
assertEquals用于双打的JUnit 方法证明了这一点:
assertEquals(double expected, double actual, double epsilon)
Run Code Online (Sandbox Code Playgroud)
那么,在这里我应该使用哪个比较?
equals方法状态的Javadoc (重点是我的):
https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-
equals方法对非null对象引用实现对等关系:
- 这是自反的:对于任何非空参考值x,x.equals(x)应该返回true。
- 它是对称的:对于任何非空参考值x和y,当且仅当y.equals(x)返回true时,x.equals(y)才应返回true。
- 它是可传递的:对于x,y和z的任何非空引用值,如果x.equals(y)返回true,而y.equals(z)返回true,则x.equals(z)应该返回true。
- 这是一致的:对于任何非空参考值x和y,只要未修改对象的equals比较中使用的信息,对x.equals(y)的多次调用将始终返回true或始终返回false。
- 对于任何非null参考值x,x.equals(null)应该返回false。
相等方法必须是可传递的。如果您使用了epsilon,则将无法保持。
考虑双值x = 2.0,y = 2.6,z = 3.1和epsilon = 1.0。
请注意,z-y = 0.5和y-x = 0.6,两者均小于1.0的ε。然而,Z - X = 1.1这是更大于1.0。
因此,我们将有“ x等于y”和“ y等于z”,但没有“ x等于z”,这破坏了传递性。如果这些是其他某些对象的实例变量,例如上面示例中的里程表,则会发生同样的情况。
因此,平等应该是精确的。如上所述转换为位的工作方式,也可以使用Double.compare(double d1, double d2)或将其转换为Double值,然后使用Double.compareTo(Double anotherDouble)。请注意,它们会将0.0和-0.0视为不同的数字。
https://docs.oracle.com/javase/8/docs/api/java/lang/Double.html#compare-double-double- https://docs.oracle.com/javase/8/docs/api/ java / lang / Double.html#compareTo-java.lang.Double-
为了保持哈希函数的一致性,这也很重要。
==即使对于原始双精度值,也不要使用内置的Java等式运算符。如该compareTo方法的JavaDocs中所述,等于失败NaN。(这个StackOverflow问题还提供了更多信息:为什么Java的Double.compare(double,double)是按原样实现的?)
最后一点-这不适用于上面的示例,因为使用了原始double值,但是如果您使用Double对象,请记住null在尝试将它们传递给任何Double比较函数之前先进行检查。