web-dev-qa-db-ja.com

Javaの数値の比較

Javaでは、すべての数値型はJava.lang.Numberから拡張されます。次のようなメソッドを使用することをお勧めします:

public boolean areEqual(Number first, Number second) {
    if (first != null && second != null) {
        return first.equals(second);
    }
}

Double 2.00000がint 2に等しくない場合が心配です。これらは組み込みで処理されますか?そうでない場合、Javaで簡単な数値比較関数を書く方法はありますか? (Apache commonsなどの外部ライブラリは問題ありません)

20
David

Double[〜#〜] never [〜#〜]equalsからIntegerへ。さらに、doubleDoubleと同じではありません。

Javaにはプリミティブ型と参照型があります。 Javaの真の数値型は、プリミティブであるため、Numberから拡張されません。

タイプを混在させないシステムを検討することをお勧めします。これは通常、情報を失う可能性がある、または失わない可能性のある暗黙的/明示的な変換で多くの問題を引き起こすためです。

関連する質問

intIntegerで:

Number比較:

こちらもご覧ください


混合型計算について

混合型の計算は、 Java Puzzlers の少なくとも4つのパズルの主題です。

さまざまな抜粋を次に示します。

一般的に混合型の計算を避けることが最善です[...]本質的に混乱を招くため[...]これは条件式ほど明白ではありません。混合型の比較は、システムが一方のオペランドを他方のタイプと一致するように強制するため、常に混乱を招きます。変換は目に見えないため、期待した結果が得られない場合があります

Prescription:整数型と浮動小数点型が混在する計算を避けます。浮動小数点よりも整数演算を優先します。

41

私は古いトピックを知っていますが、... Javaの2つの数値を比較するには、BigDecimalのcompareToメソッドを使用できます。BigDecimalはshortからdoubleまたはBigIntegerまでのすべてを保持できます。これに最適なクラスです。

そのため、次のような記述を試みることができます。

public int compareTo(Number n1, Number n2) {
    // ignoring null handling
    BigDecimal b1 = new BigDecimal(n1.doubleValue());
    BigDecimal b2 = new BigDecimal(n2.doubleValue());
    return b1.compareTo(b2);
}

これは確かにパフォーマンスに関して最良のアプローチではありません。これまでのところ、少なくともJDK7では次のテストが機能していました。

assertTrue(compareTo(new Integer(1), new Integer(2)) == -1);
assertTrue(compareTo(new Integer(1), new Double(2.0)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MAX_VALUE)) == -1);
assertTrue(compareTo(new Integer(1), new Double(Double.MIN_VALUE)) == 1);
assertTrue(compareTo(new Integer(1), new Double(1.000001)) == -1);
assertTrue(compareTo(new Integer(1), new Double(1.000)) == 0);
assertTrue(compareTo(new Integer(1), new Double(0.25*4)) == 0);
assertTrue(compareTo(new Integer(1), new AtomicLong(1)) == 0);
11
Lian

Objectから継承されたequals()を使用しているため、特定のメソッドは失敗します。つまり、Numberobjectsが同じであるかどうかを確認し、それらのvaluesは同じでした。

それが単なる例である場合は、回答を更新します。

polygeneの答えは、実際に私が目指していた地面をほぼカバーしています。この質問にも興味があるかもしれません: なぜJava.lang.NumberはComparableを実装しないのですか?

6
Pops

オブジェクト参照が同じであるかどうかを知りたい場合は、既存のメソッドが適切です。 2.0を表すDouble2を表すIntegerは、明らかに異なるオブジェクトであり、一般的な意味で交換可能ではありません。

数値が同じかどうかだけを知りたい場合は、 Number.doubleValue() メソッドを使用して両方の数値をdoubleに変換し、それらの数値を比較します(おそらく小さな許容誤差を考慮してください) 、ほとんどの数値は正確に表されていないため、中間の計算ステップに応じて、2のはずの1.99999999996583など)。次のようなもの:

private static final double EPSILON = 0.000000000000001d;    

public static boolean areEquivalentNumbers(Number a, Number b)
{
   if (a == null)
   {
      return b == null;
   }
   else if (b == null)
   {
      return false;
   }
   else
   {
      return Math.abs(a.doubleValue() - b.doubleValue()) < EPSILON;
   }
}
4
Andrzej Doyle

いくつかの応答に接して、次のようなものを書く代わりに、次のことを提案できますか?

boolean compare(Object o1, Object o2)
{
  if (o1==null)
    return o2==null;
  if (o2==null)
    return false;
  return o1.equals(o2);
}

次のように書く方がはるかに簡潔で、少し効率的だと思います。

boolean compare(Object o1, Object o2)
{
  return o1==o2 || o1!=null && o2!=null && o1.equals(o2);
}

両方がヌルの場合、o1 == o2はtrueを返します。そうではないが、同じオブジェクトであれば、それでも問題ありません。

技術的には、o2!= nullはほとんどのequalsの実装には必要ありませんが、上記の例のようにオブジェクトでこれを行うほど実際に汎用的である場合、すべてのオーバーライドがどのように記述されているかわかりません。

1
Jay

整数と浮動小数点の数値を比較しても、目的の結果が得られることはほとんどありません。ただし、これが簡単な演習である場合は、次のように値の文字列表現を比較して比較を実装できます。

public boolean areEqual(Number first, Number second) {
    if (first == null) {
        return second == null;
    }
    if (second == null) {
        return false;
    }

    return first.toString().equals(second.toString());
}
1
rsp