Ana*_*and 26 java floating-point double equals
我正在阅读Joshua Bloch的有效java和第8项:当覆盖等于时遵守一般合同,这个陈述是写的
对于float字段,使用Float.compare方法; 对于双字段,请使用Double.compare.浮法和双场的特殊处理是由Float.NaN,-0.0f和类似的双常数的存在所必需的;
有人可以解释我为什么我们不能==
用于浮动或双重比较
lin*_*ski 18
从apidoc, Float.compare
:
比较两个指定的浮点值.返回的整数值的符号与调用返回的整数的符号相同:
new Float(f1).compareTo(new Float(f2))
以数字方式比较两个Float对象.当应用于原始浮点值时,此方法执行的比较有两种不同于Java语言数值比较运算符(<,<=,==,> =>)执行的比较:
- 此方法认为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
Run Code Online (Sandbox Code Playgroud)
输出不正确,因为不是数字的东西根本不是数字,从数字比较的角度来看应该被视为相等.很明显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)
}
Run Code Online (Sandbox Code Playgroud)
根据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为真.
但请注意,Math.min和Math.max方法将负零视为严格小于正零.
对于操作数为正零和负零的严格比较,结果将是错误的.
根据IEEE 754标准的规范确定的浮点比较结果如下:
根据IEEE 754标准的规则执行浮点相等性测试:
如果任一操作数是NaN,则==的结果为false,但!=的结果为true.实际上,当且仅当x的值是NaN时,测试x!= x才为真.Float.isNaN和Double.isNaN方法也可用于测试值是否为NaN.
正零和负零被认为是相等的.例如,-0.0 == 0.0为true.
否则,相等运算符认为两个不同的浮点值不相等.特别是,有一个值代表正无穷大,一个值代表负无穷大; 每个比较仅与自身相等,并且每个比较不等于所有其他值.
对于两个操作数都是NaN的相等比较,结果将是错误的.
由于总排序(=
,<
,>
,<=
,>=
)被许多重要的算法(参见实现Comparable接口的所有类),最好是用比较的方法,因为它会产生更一致的行为.
在IEEE-754标准的上下文中总排序的结果是正零和负零之间的差异.
例如,如果你使用等于运算符而不是compare方法,并且有一些值的集合,你的代码逻辑根据元素的顺序做出一些决定,并且你以某种方式开始获得NaN值的剩余,他们将全部被视为不同的值而不是相同的值.
这可能会在程序的行为中产生与NaN值的量/速率成比例的误差.如果你有很多正负零,那只是一对会影响你的逻辑错误.
Float 使用 IEEE-754 32位格式,Double 使用 IEEE-754 64位格式.
float
(和double
)有一些特殊的比特序列保留用于非"数字"的特殊含义:
0xff800000
0x7f800000
0x7fc00000
0
与自身使用时相比,这些返回中的每一个(意味着它们都是"相同的")Float.compare()
,但以下比较使用==
与此不同 Float.NaN
:
Float.NEGATIVE_INFINITY == Float.NEGATIVE_INFINITY // true
Float.POSITIVE_INFINITY == Float.POSITIVE_INFINITY // true
Float.NaN == Float.NaN // false
Run Code Online (Sandbox Code Playgroud)
因此,在比较float
值时,要使所有值(包括特殊Float.NaN
值)保持一致,Float.compare()
是最佳选择.
这同样适用于double
.
归档时间: |
|
查看次数: |
46650 次 |
最近记录: |