为什么我们不能使用 '==' 来比较两个浮点数或双精度数
我正在阅读 Joshua Bloch 的 Effective java,在 Item 8: Obey the general contract when overriding equals 中写了这个语句
I am reading Effective java by Joshua Bloch and in Item 8: Obey the general contract when overriding equals, this statement is written
对于浮点字段,使用 Float.compare 方法;对于双字段,请使用双重比较.对float和double字段做了特殊处理Float.NaN、-0.0f 和类似的 double 的存在是必要的常量;
for float fields, use the Float.compare method; and for double fields, use Double.compare. The special treatment of float and double fields is made necessary by the existence of Float.NaN, -0.0f and the analogous double constants;
谁能举例说明为什么我们不能使用 ==
进行浮点或双重比较
Can someone explain me with example why we can't use ==
for float or double comparison
推荐答案
来自 apidoc,Float.compare
:
From apidoc, Float.compare
:
比较两个指定的浮点值.返回的整数值的符号与调用将返回的整数的符号相同:
Compares the two specified float values. The sign of the integer value returned is the same as that of the integer that would be returned by the call:
new Float(f1).compareTo(new Float(f2))
new Float(f1).compareTo(new Float(f2))
浮动.比较对象
:
比较两个 Float 对象的数值.当应用于原始浮点值时,此方法执行的比较与 Java 语言数值比较运算符(<、<=、==、>= >)执行的比较有两种不同之处:
Compares two Float objects numerically. There are two ways in which comparisons performed by this method differ from those performed by the Java language numerical comparison operators (<, <=, ==, >= >) when applied to primitive float values:
- 此方法认为 Float.NaN 等于其自身并且大于所有其他浮点值(包括 Float.POSITIVE_INFINITY).
- 此方法认为0.0f大于-0.0f.
这确保了此方法强加的 Float 对象的自然顺序与 equals 一致.
考虑以下代码:
System.out.println(-0.0f == 0.0f); //true
System.out.println(Float.compare(-0.0f, 0.0f) == 0 ? true : false); //false
System.out.println(Float.NaN == Float.NaN);//false
System.out.println(Float.compare(Float.NaN, Float.NaN) == 0 ? true : false); //true
System.out.println(-0.0d == 0.0d); //true
System.out.println(Double.compare(-0.0d, 0.0d) == 0 ? true : false);//false
System.out.println(Double.NaN == Double.NaN);//false
System.out.println(Double.compare(Double.NaN, Double.NaN) == 0 ? true : false);//true
输出不正确,因为不是数字的东西,根本就不是数字,从数字比较的角度来看,应该被视为相等.0=-0
.
The ouput is not correct, since something that is not a number, is simply not a number, and should be treated as equal from number comparison point of view. It is also clear that 0=-0
.
让我们看看 Float.compare
会:
Let's see what Float.compare
does:
public static int compare(float f1, float f2) {
if (f1 < f2)
return -1; // Neither val is NaN, thisVal is smaller
if (f1 > f2)
return 1; // Neither val is NaN, thisVal is larger
int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);
return (thisBits == anotherBits ? 0 : // Values are equal
(thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN)
1)); // (0.0, -0.0) or (NaN, !NaN)
}
Float.floatToIntBits
:
根据IEEE 754 浮点单一格式"位布局返回指定浮点值的表示形式.第 31 位(掩码 0x80000000 选择的位)表示浮点数的符号.位 30-23(由掩码 0x7f800000 选择的位)表示指数.位 22-0(由掩码 0x007fffff 选择的位)表示浮点数的有效位(有时称为尾数).
Returns a representation of the specified floating-point value according to the IEEE 754 floating-point "single format" bit layout. Bit 31 (the bit that is selected by the mask 0x80000000) represents the sign of the floating-point number. Bits 30-23 (the bits that are selected by the mask 0x7f800000) represent the exponent. Bits 22-0 (the bits that are selected by the mask 0x007fffff) represent the significand (sometimes called the mantissa) of the floating-point number.
如果参数为正无穷大,则结果为 0x7f800000.
If the argument is positive infinity, the result is 0x7f800000.
如果参数为负无穷大,则结果为 0xff800000.
If the argument is negative infinity, the result is 0xff800000.
如果参数为 NaN,则结果为 0x7fc00000.
If the argument is NaN, the result is 0x7fc00000.
在所有情况下,结果都是一个整数,当将它提供给 intBitsToFloat(int) 方法时,将产生一个与 floatToIntBits 的参数相同的浮点值(除了所有 NaN 值都折叠为单个规范"NaN 值).
In all cases, the result is an integer that, when given to the intBitsToFloat(int) method, will produce a floating-point value the same as the argument to floatToIntBits (except all NaN values are collapsed to a single "canonical" NaN value).
来自 JLS 15.20.1.数值比较运算符 <、<=、> 和 >=
根据 IEEE 754 标准的规范确定的浮点比较结果是:
The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:
如果任一操作数为 NaN,则结果为 false.
If either operand is NaN, then the result is false.
除 NaN 之外的所有值都是有序的,负无穷小于所有有限值,正无穷大于所有有限值.
All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.
正零和负零被认为是相等的.例如,-0.0<0.0 为假,但 -0.0<=0.0 为真.
Positive zero and negative zero are considered equal. For example, -0.0<0.0 is false, but -0.0<=0.0 is true.
但请注意,Math.min 和 Math.max 方法将负零视为严格小于正零.
Note, however, that the methods Math.min and Math.max treat negative zero as being strictly smaller than positive zero.
对于操作数为正零和负零的严格比较,结果将是错误的.
For strict comparisons where operands are positive zero and negative zero the result will be wrong.
来自 JLS 15.21.1.数值等式运算符 == 和 !=:
根据 IEEE 754 标准的规范确定的浮点比较结果是:
The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:
浮点相等性测试是按照 IEEE 754 标准的规则进行的:
Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:
如果任一操作数为 NaN,则 == 的结果为假,但 != 的结果为真.实际上,当且仅当 x 的值为 NaN 时,测试 x!=x 为真.Float.isNaN 和 Double.isNaN 方法也可以用来测试一个值是否为 NaN.
If either operand is NaN, then the result of == is false but the result of != is true. Indeed, the test x!=x is true if and only if the value of x is NaN. The methods Float.isNaN and Double.isNaN may also be used to test whether a value is NaN.
正零和负零被认为是相等的.例如,-0.0==0.0 为真.
Positive zero and negative zero are considered equal. For example, -0.0==0.0 is true.
否则,相等运算符会认为两个不同的浮点值不相等.特别是,有一个值表示正无穷大,一个值表示负无穷大;each 仅与自身比较相等,并且 each 与所有其他值比较不相等.
Otherwise, two distinct floating-point values are considered unequal by the equality operators. In particular, there is one value representing positive infinity and one value representing negative infinity; each compares equal only to itself, and each compares unequal to all other values.
对于两个操作数都是 NaN 的相等比较,结果将是错误的.
For equality comparisons where both operands are NaN the result will be wrong.
由于总排序(=
, <
, >
,<=
, >=
) 被许多重要的算法使用(参见 所有实现 Comparable 接口的类) 最好使用 compare 方法,因为它会产生更一致的行为.
Since total ordering (=
, <
, >
,<=
, >=
) is used by many important algorithms (see all the classes that implement the Comparable interface) it is better to use the compare method because it will yield more consistent behavior.
IEEE-754 标准上下文中的总排序的结果是正负零.
例如,如果您使用相等运算符而不是比较方法,并且有一些值集合,并且您的代码逻辑根据元素的顺序做出一些决定,并且您以某种方式开始获得多余的 NaN 值,那么它们'将被视为不同的值,而不是相同的值.
For instance, if you use the equality operator instead of the compare method, and have some collection of values and your code logic makes some decisions based on the ordering of the elements, and you somehow start getting a surplus of NaN values they'll all be treated as different values instead as the same values.
这可能会在程序的行为中产生与 NaN 值的数量/比率成比例的错误.如果你有很多正零和负零,那只是一对会影响你的逻辑错误.
That may likely produce error in the behavior of the program proportional to the amount/rate of NaN values. And if you have a lot of positive and negative zeroes, that's just one pair to affect your logic with error.
浮点 使用 IEEE-754 32 位格式和双精度 使用 IEEE-754 64位格式.
Float uses IEEE-754 32 bit format and Double uses IEEE-754 64 bit format.
相关文章