有人能否举个例子解释一下为什么我们不能使用对于float类型的字段,请使用Float.compare方法;对于double类型的字段,请使用Double.compare。之所以对float和double类型的字段进行特殊处理,是因为存在Float.NaN、-0.0f以及类似的double常量。
==
来比较float或double呢?有人能否举个例子解释一下为什么我们不能使用对于float类型的字段,请使用Float.compare方法;对于double类型的字段,请使用Double.compare。之所以对float和double类型的字段进行特殊处理,是因为存在Float.NaN、-0.0f以及类似的double常量。
==
来比较float或double呢?从apidoc中了解到,Float.compare
的作用是比较两个指定的浮点数值。返回的整数值与以下代码的返回值相同:
new Float(f1).compareTo(new Float(f2))
该整数值的符号与通过上述代码调用返回的整数的符号相同。
比较两个浮点数对象的大小。当应用于原始的浮点值时,该方法执行的比较和Java语言中的数值比较运算符(<、<=、==、>=、>)有两种不同之处: 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
。Float.compare
做了什么: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)
}
根据IEEE 754浮点数“单格式”位布局的规定,返回指定浮点值的表达式。第31位(由掩码0x80000000选择的位)表示浮点数的符号。第30-23位(由掩码0x7f800000选择的位)表示指数。第22-0位(由掩码0x007fffff选择的位)表示浮点数的尾数(有时称为“曼蒂萨”)。如果参数是正无穷大,则结果为0x7f800000。如果参数是负无穷大,则结果为0xff800000。如果参数是NaN,则结果为0x7fc00000。在所有情况下,结果都是一个整数,当给intBitsToFloat(int)方法时,它将产生与floatToIntBits的参数相同的浮点值(除了所有NaN值均折叠为单个“规范”NaN值)。
来自JLS 15.20.1. 数值比较运算符 <, <=, >, 和 >=
根据IEEE 754标准的规定,浮点数比较的结果如下:
如果任一操作数为NaN,则结果为false。
所有非NaN值都是有序的,负无穷小于所有有限值,正无穷大于所有有限值。
正零和负零被认为是相等的。例如,-0.0<0.0为false,但-0.0<=0.0为true。
然而,请注意,方法Math.min和Math.max将负零视为严格小于正零。
对于严格比较,其中操作数为正零和负零,结果将是错误的。
来自JLS 15.21.1. 数值相等运算符 == 和 !=:
根据IEEE 754标准的规定,浮点数比较的结果为:
浮点数相等性测试遵循IEEE 754标准的规则:
如果任一操作数为NaN,则==的结果为false,但!=的结果为true。实际上,当且仅当x的值为NaN时,测试x!= x为true。方法Float.isNaN和Double.isNaN也可用于测试一个值是否为NaN。
正零和负零被认为是相等的。例如,-0.0 == 0.0为true。
否则,相等运算符将两个不同的浮点值视为不相等。特别地,有一个表示正无穷大和一个表示负无穷大的值;每个值只与自身相等,并且与所有其他值都不相等。
对于两个操作数都是 NaN 的相等比较,结果将会是错误的。
由于全序关系(=
, <
, >
,<=
, >=
)被许多重要的算法所使用(参见所有实现Comparable接口的类),因此最好使用compare方法,因为它会产生更一致的行为。
在 IEEE-754 标准下,全序关系的后果是正零和负零之间的差异。
例如,如果您使用等号运算符而非 compare 方法,并且有一些值的集合,您的代码逻辑基于元素的顺序做出一些决策,以某种方式开始获取 NaN 值的剩余部分,则它们将被视为不同的值而不是相同的值。
这可能会导致程序行为的错误与NaN值的数量/比例成正比。如果您有很多正零和负零,那么只有一对就足以通过错误影响您的逻辑。
float
(和double
)具有一些特殊的位序列,用于保留非“数字”的特殊含义:
0xff800000
0x7f800000
0x7fc00000
使用Float.compare()
将它们与自身进行比较时,每个值都会返回0
(表示它们“相同”),但是对于Float.NaN
,以下使用==
进行的比较则与此不同:
Float.NEGATIVE_INFINITY == Float.NEGATIVE_INFINITY // true
Float.POSITIVE_INFINITY == Float.POSITIVE_INFINITY // true
Float.NaN == Float.NaN // false
因此,当比较 float
值时,为了对所有值保持一致性,包括特殊的 Float.NaN
值,最好使用 Float.compare()
。
对于 double
同样适用。
Float.compare()
返回一个int
,而不是"false"(假)或"true"(真)。所有后续对Float.compare()
的调用都返回0:Float.compare(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY)
、Float.compare(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY)
和 Float.compare(Float.NaN, Float.NaN)
。我确定这一点,因为我刚刚执行了它。 - Bohemiancompare()
的Javadoc中了)。 - Bohemian比较浮点对象有两个原因:
==
运算符提供了数学比较。对于 NaN == NaN
返回 false,对于 -0.f == +0.f
返回 true。
compare
和 compareTo
程序提供了对象比较。当将 NaN 与自身进行比较时,它们表明它们是相同的(通过返回零)。当将 -0.f
与 +0.f
进行比较时,它们表明它们是不同的(通过返回非零值)。
NaN == NaN
是false。但是,compare
的官方规范并没有给出有关如何处理“奇怪”情况的详细信息。更重要的是要记住,在除了特殊情况之外,永远不要进行“相等”的比较,除非你知道自己在做什么。 - Hot Licks20000000
和20000001
这两个浮点数进行比较,如果使用==
来比较,它们是不相等的! - devnull