Java整数compareTo()-なぜ比較と減算を使用するのですか?


80

私は見つけたjava.lang.Integerの実装compareToは次のような方法のルックスを:

public int compareTo(Integer anotherInteger) {
    int thisVal = this.value;
    int anotherVal = anotherInteger.value;
    return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
}

問題は、なぜ減算の代わりに比較を使用するのかということです。

return thisVal - anotherVal;

27
マイクロ最適化についてすぐに心配すると、コードにバグが発生することがよくあります。
Kevin Bourrillion 2010

JDK 7以降でInteger.compare(thisVal, anotherVal)は、3値式を書き出す代わりに使用できます。
スチュアートマークス

回答:


96

これは整数オーバーフローが原因です。ときにthisVal非常に大きく、anotherVal負は前者収率よりも大きい結果から後者を引いているthisVal負の範囲にオーバーフローする可能性があります。


ええ、彼らがここでそれを行った方法は、オーバーフローなどをチェックするよりもおそらく効率的です
rogerdpack 2011年

GuavaComparisonChainを使用します。とても便利です!google.github.io/guava/releases/22.0/api/docs/com/google/common/...
アンドレアBergonzo

thisVal大きくする必要はありません。thisValでもゼロになると、可能性があるanotherValことがInteger.MIN_VALUE、あなたはすでにオーバーフローを持っています。もちろん、値の範囲を超える距離を持つことは、逆にthisValue非常に小さく、anotherValかなり大きい可能性があることに注意してintください。
ホルガー

65

2つの数値を比較するための減算「トリック」が壊れています!!!

        int a = -2000000000;
        int b =  2000000000;
        System.out.println(a - b);
        // prints "294967296"

ここではa < b、まだa - bポジティブです。

このイディオムは使用しないでください。動作しません。

また、それは仕事をしていても、それはなりませ大幅な性能の向上、および5月実際にはコストの読みやすさを提供しています。

も参照してください

  • Javaパズルパズル65:疑わしいソートの奇妙な佐賀

    このパズルにはいくつかのレッスンがあります。最も具体的な方法は次のとおりです Integer.MAX_VALUE値の差がより大きくならないことが確実でない限り、減算ベースのコンパレータを使用しないでください。より一般的には、intオーバーフローに注意してください。もう1つの教訓は、「賢い」コードは避けるべきだということです。明確で正しいコードを書くように努め、必要であることが証明されない限り、それを最適化しないでください。


2
まったく壊れていません。比較している数値について何か知っている場合は、それらが安全に比較できることをおそらく知っているでしょう。知らなくても、うまくいく((long)a - b)はずです。あなたは正しいのに; あまり役に立たない。
amara 2010年

4
@naiadを実行するだけで((long)a - b)は役に立ちません。結果をにキャストし直す必要があるためです。これはint、コンパレータが返す必要があるものであり、オーバーフローが発生するためです。あなたのLong.signumコメントが示すように、あなたは結果に対して何かをしなければならないでしょう、それは忘れがちです。そしてInteger.compare、JVMが本質的に処理する可能性があるよりも効率的ではないかもしれません…
Holger

9

簡単に言えば、intタイプは2つの任意のint値の差を格納するのに十分な大きさではありません。たとえば、15億と-15億の差は30億ですがint、21億を超える値を保持することはできません。



1

オーバーフローに加えて、減算を使用たバージョンでは同じ結果が得られないことに注意してください。

  • 最初のcompareToバージョンは、-1、0、または1の3つの可能な値のいずれかを返します。
  • 最後の行を減算に置き換えると、結果は任意の整数値になります。

オーバーフローが発生しないことがわかっている場合は、次のようなものを使用できます。

public int compareTo(Integer anotherInteger) {
    return sign(this.value - anotherInteger.valuel);
}

12
あなたは結果が同じではないということは正しいです。しかし、そうである必要はありません!および他のオブジェクトのcompareToソート順に応じて、負の値、ゼロ、または正の値を返すためにのみ必要ですthisjava.sun.com/j2se/1.5.0/docs/api/java/lang/…を
Christian Semrau 2010
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.