1. ホーム

[解決済み】if (a - b < 0)とif (a < b)の違いについて)

2022-04-05 03:48:53

質問

Java の ArrayList のソースコードで、ifステートメントでいくつかの比較に気づきました。

Java 7 では、メソッド grow(int) が使用します。

if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;

Java 6の場合。 grow は存在しなかった。メソッド ensureCapacity(int) を使用します。

if (newCapacity < minCapacity)
    newCapacity = minCapacity;

変更の理由は何だったのでしょうか?パフォーマンスの問題なのか、それとも単なるスタイルなのか?

ゼロと比較した方が速いのは想像がつきますが、マイナスかどうかをチェックするためだけに完全な引き算をするのは、ちょっとやりすぎな気がします。また、バイトコードの面でも、これは2つの命令( ISUBIF_ICMPGE )ではなく、1つ( IFGE ).

解決方法は?

a < ba - b < 0 は、2つの異なる意味を持つことがあります。次のようなコードを考えてみましょう。

int a = Integer.MAX_VALUE;
int b = Integer.MIN_VALUE;
if (a < b) {
    System.out.println("a < b");
}
if (a - b < 0) {
    System.out.println("a - b < 0");
}

実行すると、次のように表示されます。 a - b < 0 . 何が起こるかというと a < b は明らかに誤りですが a - b がオーバーフローして -1 であり、負である。

さて,ここで,配列の長さが本当に Integer.MAX_VALUE . のコードは ArrayList はこのようになります。

int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
    newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
    newCapacity = hugeCapacity(minCapacity);

oldCapacity は本当に近い Integer.MAX_VALUE だから newCapacity (これは oldCapacity + 0.5 * oldCapacity がオーバーフローして Integer.MIN_VALUE (つまりマイナス)です。では、引き算の minCapacity アンダーフロー を正の数に戻す。

このチェックにより if は実行されません。もし、コードが if (newCapacity < minCapacity) であれば、それは true この場合、( newCapacity はマイナス)なので newCapacity に強制されることになる。 minCapacity に関係なく oldCapacity .

このオーバーフローのケースは、次のifで処理されます。いつ newCapacity がオーバーフローした場合、これは true : MAX_ARRAY_SIZE は次のように定義されます。 Integer.MAX_VALUE - 8Integer.MIN_VALUE - (Integer.MAX_VALUE - 8) > 0true . その newCapacity は正しく処理されます。 hugeCapacity メソッドは MAX_ARRAY_SIZE または Integer.MAX_VALUE .

注:これは // overflow-conscious code のコメントは、このメソッドで言っていることです。