为什么我们不能使用'=='来比较两个float或double数字 [英] Why can't we use '==' to compare two float or double numbers

查看:150
本文介绍了为什么我们不能使用'=='来比较两个float或double数字的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在阅读Joshua Bloch的有效Java,并且在第8项中:当覆盖相等于时,遵守一般合同,此语句写入


为浮动字段,使用Float.compare方法;对于双字段,使用
Double.compare。浮点和双字段的特殊处理使得
由于Float.NaN,-0.0f和类似的双
常量的存在而必需;


有人向我解释一下为什么我们不能使用 == 进行浮动或双重比较

解决方案

从apidoc, Float.compare


比较两个指定的浮点值。返回的整数值的符号与调用返回的整数的符号相同:



new Float(f1).compareTo(new Float(f2 ))


Float.compareTo


以数字方式比较两个Float对象。当应用于原始浮点值时,通过此方法执行的比较有两种方法与Java语言数值比较运算符(<,=,==,> =>)执行的比较:




  • 此方法认为Float.NaN等于其本身并大于所有其他浮点值(包括Float.POSITIVE_INFINITY)。

  • 0.0f被认为是大于-0.0f。




考虑以下代码:

  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.comNot,Double.NaN)== 0?true:false); // true

输出不正确,因为不是数字的东西根本不是数字,应该被视为等于数字比较的观点。也很清楚, 0 = -0



我们来看看Float .compare

  public static int compare(float f1,float f2) {
if(f1&f2)
return -1; //两者都不是NaN,这个值更小
if(f1> f2)
return 1; //两者都不是NaN,这个值大于

int thisBits = Float.floatToIntBits(f1);
int anotherBits = Float.floatToIntBits(f2);

return(thisBits == anotherBits?0://值相等
(thisBits< anotherBits?-1://(-0.0,0.0)或(!NaN,NaN)
1)); //(0.0,-0.0)或(NaN,!NaN)
}

a href =http://docs.oracle.com/javase/6/docs/api/java/lang/Float.html#floatToIntBits%28float%29> Float.floatToIntBits


根据 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是假的,但是-0.0 <= 0.0是真的。


  • 然而,请注意,Math.min和Math.max将负零值严格小于正零。



严格比较操作数为正零和负零,结果将是错误的。



JLS 15.21.1。数值平等运算符==和!=


浮点比较的结果,由IEEE 754标准是:



根据IEEE 754标准的规则执行浮点式相似性测试:




  • 如果任一操作数为NaN,则==的结果为false,但=!的结果为true。实际上,当且仅当x的值为NaN时,测试x!= x为真。方法Float.isNaN和Double.isNaN也可用于测试值是否为NaN。


  • 正零和负零被认为是相等的。例如,-0.0 == 0.0是true。


  • 否则,两个不同的浮点值被相等运算符视为不相等。特别地,存在代表正无穷大的一个值和表示负无穷大的一个值;每个比较仅等于自身,并且每个比较与所有其他值不等。



对于两个操作数均为 NaN 的平等比较结果将是错误的。



由于总订购( = ; > < = > = 被许多重要的算法使用(参见实现Comparable界面的所有类)最好使用compare方法,因为它会产生更一致的行为。



在上下文中的总排序结果IEEE-754标准是正负零之间的差异。



例如,如果使用相等运算符而不是compare方法,并且一些值的集合和你的代码逻辑根据元素的顺序做出一些决定,你以某种方式开始获得NaN值的剩余,他们都将被视为不同的值,而不是相同的值。



这可能会导致程序的行为错误与NaN值的数量/速率成正比。如果你有很多正面和负面的零点,那么只是一对会影响你的逻辑错误。



Float 内容 IEEE-754 32位格式和Double uses IEEE-754 64位格式。


I am reading Effective java by Joshua Bloch and in Item 8: Obey the general contract when overriding equals, this statement is written

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

解决方案

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))

Float.compareTo:

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 is considered by this method to be equal to itself and greater than all other float values (including Float.POSITIVE_INFINITY).
  • 0.0f is considered by this method to be greater than -0.0f.

This ensures that the natural ordering of Float objects imposed by this method is consistent with equals.

Consider the following code:

    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        

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.

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:

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.

If the argument is positive infinity, the result is 0x7f800000.

If the argument is negative infinity, the result is 0xff800000.

If the argument is NaN, the result is 0x7fc00000.

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).

From JLS 15.20.1. Numerical Comparison Operators <, <=, >, and >=

The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:

  • If either operand is NaN, then the result is false.

  • All values other than NaN are ordered, with negative infinity less than all finite values, and positive infinity greater than all finite values.

  • Positive zero and negative zero are considered equal. For example, -0.0<0.0 is false, but -0.0<=0.0 is true.

  • 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.

From JLS 15.21.1. Numerical Equality Operators == and !=:

The result of a floating-point comparison, as determined by the specification of the IEEE 754 standard, is:

Floating-point equality testing is performed in accordance with the rules of the IEEE 754 standard:

  • 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.

  • Positive zero and negative zero are considered equal. For example, -0.0==0.0 is true.

  • 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.

For equality comparisons where both operands are NaN the result will be wrong.

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.

The consequence of the total ordering in the context of the IEEE-754 standard is the difference between the positive and negative zero.

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.

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.

Float uses IEEE-754 32 bit format and Double uses IEEE-754 64 bit format.

这篇关于为什么我们不能使用'=='来比较两个float或double数字的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆