3

Java で次のメソッドを検討してください。

public static boolean expensiveComputation() {
    for (int i = 0; i < Integer.MAX_VALUE; ++i);
    return false;
}

そして、次の主な方法:

public static void main(String[] args) {
    boolean b = false;
    if (expensiveComputation() && b) {
    }
}

論理積 (&& と同じ) は可換演算です。では、コンパイラが if ステートメント コードを同等のものに最適化しないのはなぜですか。

if (b && expensiveComputation()) {
}

短絡評価を使用する利点はどれですか?

さらに、コンパイラは、より高速なコードを生成するために、他のロジックの単純化やブール値の置換を試みますか? そうでない場合、なぜですか?確かにいくつかの最適化は非常に難しいでしょうが、私の例は単純ではありませんか? メソッドの呼び出しは、ブール値の読み取りよりも常に遅くなるはずですよね?

前もって感謝します。

4

5 に答える 5

17

costComputation() には、プログラムの状態を変更する副作用がある可能性があるため、これは行いません。これは、ブール ステートメントの式が評価される順序 (expensiveComputation() および b) が重要であることを意味します。コンパイラがコンパイル済みプログラムのバグを最適化することを望まないでしょうか?

例えばこんなコードだったら

public static boolean expensiveComputation() {
        for (int i = 0; i < Integer.MAX_VALUE; ++i);
        b = false;
        return false;
}

public static boolean b = true;
public static void main(String[] args) {
        if (expensiveComputation() || b) {
        // do stuff
        }
}

ここで、コンパイラが最適化//do stuffを実行した場合、コードを見て期待しないときに が実行されます (元は true である b が最初に評価されるため)。

于 2009-08-28T17:55:40.903 に答える
8

expensiveComputation()副作用が出る可能性があるからです。

Java は機能的に純粋な言語を目指していないため、プログラマーが副作用のあるメソッドを作成することを妨げません。したがって、関数の純粋性を分析するコンパイラーには、おそらくあまり価値がありません。そして、あなたが主張するような最適化は、expensiveComputation()副作用を得るために通常とにかく実行する必要があるため、実際には非常に価値があるとは考えられません。

もちろん、プログラマーにとって、それbが偽であると予想し、コストのかかる計算を明示的に避けたい場合、最初に置くのは簡単です。

于 2009-08-28T17:55:44.757 に答える
2

実際、一部のコンパイラは、あなたが提案したようなプログラムを最適化できますが、関数に副作用がないことを確認するだけです。GCC には、関数に注釈を付けて副作用がないことを示すことができるコンパイラ ディレクティブがあり、コンパイラは最適化時にこれを使用できます。Javaにも似たようなものがあるかもしれません。

古典的な例は

for(ii = 0; strlen(s) > ii; ii++) < 何かをする >

に最適化されます

n = strlen(s); for(ii = 0; n > ii; ii++) < 何かをする >

少なくとも私のマシンでは、最適化レベル2のGCCによって。

于 2009-08-29T09:13:16.023 に答える
0

私が使用している Java のバージョンは、式では a を最適化しますa && bが、b では最適化しません。

つまり、a が false の場合、b は評価されませんが、b が false の場合は評価されません。

Web サイトのフォームに検証を実装していたときに、これを発見しました。一連のブール メソッドで Web ページに表示するメッセージを作成しました。誤って入力されたページ内のフィールドが強調表示されることを期待していましたが、Java のスピードハックにより、コードは最初の誤ったフィールドが発見されるまでしか実行されませんでした。その後、Java は「false && なんでも常に false」のようなことを考えて、残りの検証メソッドをスキップしたに違いありません。

あなたの質問への直接的な答えとして、このような最適化を行うと、プログラムの実行速度が遅くなる可能性があると思います。ただし、他の回答で言及されている副作用のような最適化されていない動作を想定しているため、他の誰かのプログラムは完全に壊れます。

残念ながら、特に命令型言語 (C、C++、Java、Python などの通常の言語) では、インテリジェントな決定を自動化することは困難です。

于 2015-04-24T15:35:23.077 に答える
0

おそらくメソッドをインライン化し、結果のブール式を単純化することにより、コードを十分に頻繁に実行すると、コンパイラーはこれを最適化します (ただし、&& の引数を並べ替えることはほとんどありません)。

このコードを繰り返し 100 万回繰り返すループのタイミングを計ることで、これをベンチマークできます。最初の 1 回または 2 回の反復は、次の反復よりもはるかに遅くなります。

于 2009-08-29T08:42:55.177 に答える