Analyzing the Java floating point equality
Problem is described as follows:
Given two variables double a, double b, their corresponding variables are the type of packing Double x, Double y, Q:
- If there is a group of a, b, x, y, meet a == b &&! X.equals (y)?
- If there is a group of a, b, x, y, meet a! = B && x.equals (y)?
At first glance it seems impossible, in fact, the existence of such a value, refer to the following codes
public static void main() {
double a = 0.0;
double b = -0.0;
double c = Double.NaN;
double d = Double.NaN;
Double x = a;
Double y = b;
Double z = c;
Double w = d;
System.out.println(a == b); //输出true
System.out.println(x.equals(y)); //输出false
System.out.println(c == d); //输出false
System.out.println(w.equals(z)); //输出true
}
Double type equals
implement and method ==
Operators Logical vary.
Look ==
operator to Java8 example, according to the Java Language Specification 15.21.1 , for floating point equality tests, compliant IEEE 754 specification:
- As long as there is one operand is
NaN
,==
the result of the expression is always false,!=
the result of the expression is always true. In fact, if and only ifx
the valueNaN
, the expressionx!=x
is true. You can useFloat.NaN
a method or aDouble.NaN
method of determining whether a valueNaN
. - Positive and negative 0 is equal to 0, for example, the expression
0.0==-0.0
is true. - In addition, the use of two different floating-point
==
or!=
when the operator determines equality, recognize that they are not equal. In particular, a positive value indicates infinity, a value representing negative infinity; if they are compared with themselves, are equal; compared with other values are not equal.
Look at the JDK Double equals method to achieve:
public boolean equals(Object obj) {
return (obj instanceof Double)
&& (doubleToLongBits(((Double)obj).value) ==
doubleToLongBits(value));
}
/**
* Returns a representation of the specified floating-point value
* according to the IEEE 754 floating-point "double
* format" bit layout.
*
* <p>Bit 63 (the bit that is selected by the mask
* {@code 0x8000000000000000L}) represents the sign of the
* floating-point number. Bits
* 62-52 (the bits that are selected by the mask
* {@code 0x7ff0000000000000L}) represent the exponent. Bits 51-0
* (the bits that are selected by the mask
* {@code 0x000fffffffffffffL}) represent the significand
* (sometimes called the mantissa) of the floating-point number.
*
* <p>If the argument is positive infinity, the result is
* {@code 0x7ff0000000000000L}.
*
* <p>If the argument is negative infinity, the result is
* {@code 0xfff0000000000000L}.
*
* <p>If the argument is NaN, the result is
* {@code 0x7ff8000000000000L}.
*
* <p>In all cases, the result is a {@code long} integer that, when
* given to the {@link #longBitsToDouble(long)} method, will produce a
* floating-point value the same as the argument to
* {@code doubleToLongBits} (except all NaN values are
* collapsed to a single "canonical" NaN value).
*
* @param value a {@code double} precision floating-point number.
* @return the bits that represent the floating-point number.
*/
public static long doubleToLongBits(double value) {
long result = doubleToRawLongBits(value);
// Check for NaN based on values of bit fields, maximum
// exponent and nonzero significand.
if ( ((result & DoubleConsts.EXP_BIT_MASK) ==
DoubleConsts.EXP_BIT_MASK) &&
(result & DoubleConsts.SIGNIF_BIT_MASK) != 0L)
result = 0x7ff8000000000000L;
return result;
}
Double equals method by ==
the operator, determines two objects doubleToLongBits return value is equal to that if two objects are equal. There is a method comment
If the argument is NaN, the result is 0x7ff8000000000000L
Analyzing it using equals two NaN
, the result is true.
In other cases, according to the binary value of said doubleToLongBits
return value corresponding long. And 0.0
and -0.0
different sign bit, the binary representation is different, doubleToLongBits
the results are different.