In mathematics, equal signs (=) define an equivalent relationship between real numbers (equivalence relation ). This equivalence relationship divides a set into many equivalence classes, each of which consists of all equal values. Other equivalence relationships include the "full equality" relationship on all triangle sets and the "same page number" relationship on all book sets. In fact, relationship ~ Is an equivalent relationship, and only when it is self-inverse, transmitted, and symmetric. These properties are defined as follows:
1. Self-inverse: For all X, X ~ X. That is to say, each value has a relationship with itself ~ .
2. Transmission: If X ~ Y and Y ~ Z, then x ~ Z. That is to say, if the first value has a relationship with the second value ~, The second value is related to the third value ~ , The first value also has a relationship with the third value ~ .
3. Symmetry: If X ~ Y, then Y ~ X. That is to say, if the first value is related to the second value ~ The second value is also related to the first value ~ .
If you read puzzle 29, you can know that the operator = is not self-inverse, because the expression (double. nan = double. NAN) value is false, expression (float. nan = float. NAN. But does the operator = violate symmetry and transmission? In fact, it does not violate symmetry: For all x and y values, (x = y) means (y = X ). The transfer is completely another thing. Puzzle 35 provides clues about the cause of non-pass when operator = is applied to values of the original type. When comparing two original data types, the operator = first promotes binary numeric promotion [JLS 5.6.2]. This causes one of the two values to expand the original type conversion (widening primitive conversion ). Most of the original type conversion is normal, but there are three notable exceptions: When the Int or long value is converted to the float value, or the long value is converted to the double value, will cause loss of precision. This loss of precision proves the non-pass of = Operator.
The trick to achieving this non-deliverable is to use the two methods in the above three numerical values to lose the accuracy, and then we can get the opposite result. An example can be constructed as follows: select two large but different long numeric values to X and Z, and assign a double numeric value similar to the previous two long numeric values to y. The following program is its code. The printed result is true, true, and false, which obviously proves that the operator = is not passed when it acts on the original type.
public class Transitive { public static void main(String[] args) throws Exception { long x = Long.MAX_VALUE; double y = (double) Long.MAX_VALUE; long z = Long.MAX_VALUE - 1; System.out.print((x == y) + “ “); // Imprecise! System.out.print((y == z) + “ “); // Imprecise! System.out.println(x == z); // Precise! }}
The lesson of this puzzle is to be aware of the loss caused by the conversion of the original types of float and double types. They are silent, but fatal. They violate your instincts and can cause very subtle errors (see puzzle 34 ). More generally, be cautious with mixed-type operations (puzzles 5, 8, 24, and 31 ). The lessons learned by this puzzle for Language designers are the same as those in question 34: the loss of silent precision confused programmers.
Question 87: Tension