12

最小または最大の2つの数値/関数と比較する場合、最初のケースが真であり、2番目のケースが真である場合、C#は短絡しますか?これらのケースの具体例は次のとおりです。

if(x < Math.Max(y, z()))

if(x > Math.Min(y, z()))

は少なくともyと同じ大きさの値を返すためMath.Max(y, z())、x <yの場合、z()を評価する必要はありません。これには時間がかかる場合があります。と同様の状況Math.Min

これらは両方とも次のように書き直すことができると思います

if(x < y || x < z())

短絡させるためですが、書き直さなくても比較がより明確になると思います。これは短絡しますか?

4

5 に答える 5

18

他の人が指摘しているように、コンパイラは、メソッドが呼び出される前に引数が評価されるというルールを破ることができるMinまたはMaxのセマンティクスについては何も知りません。

自分で書きたい場合は、簡単に書くことができます。

static bool LazyLessThan(int x, int y, Func<int> z)
{
    return x < y || x < z();
}

それからそれを呼びます

if (LazyLessThan(x, y, z))

また

if (LazyLessThan(x, y, ()=>z()))

またはそのことについて:

static bool LazyRelation<T>(T x, T y, Func<T> z, Func<T, T, bool> relation)
{
    return relation(x, y) || relation(x, z());
}
...
if (LazyRelation(x, y, ()=>z, (a,b)=> a < b))) 
于 2012-01-18T19:27:19.810 に答える
10

いいえ、短絡することはなく、z()は常に評価されます。短絡動作が必要な場合は、行ったように書き直す必要があります。

于 2012-01-18T19:13:07.643 に答える
5

Math.Min()Math.Max()は他のメソッドと同じです。比較の2番目の引数として使用される値を返すために、これらを評価する必要があります。短絡が必要な場合は、説明したように||演算子を使用して条件を記述する必要があります。

于 2012-01-18T19:14:07.483 に答える
3

(特に新しいものはありませんが、実行したテストの結果を共有すると思いました。)

Math.Max()は、CLRのジャストインタイムコンパイラーによって簡単にインライン化でき、そこから、コードが短絡するようにコードをさらに最適化できるかどうかに興味がありました。

そこで、2つの式をそれぞれ1,000,000回評価するマイクロベンチマークを作成しました。z()には、再帰的な方法を使用してFib(15)を計算する関数を使用しました。2つを実行した結果は次のとおりです。

x < Math.Max(y, z()) :   8097 ms
x < y || x < z()     :     29 ms

CLRは、ルーチンに副作用があるかどうかを知らない(そして確認しない)ため、メソッド呼び出しの実行を妨げるような方法でコードを変換しないと思います。

于 2012-01-18T20:34:46.830 に答える
2

いいえ、少なくともC#コンパイラレベルでは短絡しません。Math.MinまたはMath.Max、2つの通常の静的メソッド呼び出しであり、コンパイラはその意味で最適化されません。

コードの評価の順序は次のようになります:z()、Math.Max、x>..。

本当に確認したい場合は、ILコードを確認してください。

于 2012-01-18T19:13:45.787 に答える