【问题标题】:Java doesn't seem to be comparing Doubles rightJava 似乎并没有正确比较双精度数
【发布时间】:2008-12-26 01:35:20
【问题描述】:

我创建了一个链接列表,具有插入、搜索和删除功能。我还为它创建了一个迭代器。现在,假设我这样做:

myList<Integer> test = new myList();
test.insert(30);
test.insert(20);
test.insert(10);
myList.iterator it = test.search(20);
if(it.hasNext())
    System.out.println(it.next());

瞧,它起作用了(它在节点上打印元素的值,在本例中为 20)。现在,如果我这样做:

myList<Double> test = new myList();
test.insert(30.1);
test.insert(20.1);
test.insert(10.1);
myList.iterator it = test.search(20.1);
if(it.hasNext())
    System.out.println(it.next());

它没有,因为迭代器指向 null。下面是搜索功能的实现:

public iterator search(T data)
{
    no<T> temp = first;
    while( (temp != null) && (temp.data != data) )
        temp = temp.next;
    return (new iterator(temp));
}

以下是我如何知道比较有问题的方法:如果我像这样更改上述代码的一部分:

while( (temp != null) && (temp.data != data) )
     System.out.println(temp.data + " " + data);
     temp = temp.next;

我可以看到它打印列表中的数字。它在某一时刻打印“20.1 20.1”(例如)。那么我该如何解决这个问题呢?该函数似乎是正确的,但似乎 Java 没有正确比较数字。

编辑:BigDecimal 也给了我同样的问题。

编辑 2:equals() 有效,没有意识到还有其他问题。对不起。

【问题讨论】:

    标签: java generics double


    【解决方案1】:

    请注意,使用 .equals() 比较 doubles 可能会导致错误。 Double.equals() 使用它作为它的相等性测试:

     d1.doubleValue() == d2.doubleValue()
    

    Doublefloats 是存储在内存中固定空间中的数字的近似值

    为了正确比较浮点数,您需要注意,由于浮点数的性质,会有一些错误。

    见:http://www.google.com/search?q=floating+point+equality

    比较双打的一种快速简便的方法是使用Math.abs(a-b)&lt;ACCEPTABLE_ERROR 其中 ACCEPTABLE_ERROR 可能是.000000000001,具体取决于您的具体操作。 (请注意,这不处理 NaN 和 INFINITY 等边缘情况)

    【讨论】:

      【解决方案2】:

      您不希望使用 != 运算符。它比较参考。你想要.equals() 方法:

      public iterator search(T data)
      {
          no<T> temp = first;
          while (!data.equals(temp.data)) {
              temp = temp.next;
          }
          return (new iterator(temp));
      }
      

      另外,请注意auto-boxing。您可能会发现 test.search(20.1) 将 20.1 框到 Float 而不是 Double,这可能会破坏您的比较。将结果与test.search(20.1d) 进行比较。如果我没记错的话,表达式:

      new Float(20.1).equals(new Double(20.1))
      

      是假的。

      【讨论】:

      • Java 中的常量 20.1 总是被解释为双精度数,即 20.1d。因此 20.1 将始终自动装箱为 Double。 Float 有一个采用 double 的构造函数(奇怪的是,我认为),这就是为什么您的第二个示例编译没有错误的原因。
      • 注意 IEEE 754 格式 (en.wikipedia.org/wiki/IEEE_754) 中的相等比较。如果计算出的数字由于表示和/或舍入问题,您最终可能会发现 0.2 不等于 1/5(不知道确切的示例)。
      • 整数在 -128 到 127 之间的装箱需要每次都返回相同的整数(对于其他值可能会这样做)。这就是整数版本恰好可以工作的原因。如果错误使用 ==/!=,FindBugs 会(可能)警告您。
      猜你喜欢
      • 2012-12-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多