По сравнению с Math.Min или Math.Max короткое замыкание?
Если сравнивать с минимумом или максимумом двух чисел/функций, происходит ли короткое замыкание на С#, если это верно для первого и будет означать истину для второго? Конкретными примерами этих случаев являются
if(x < Math.Max(y, z()))
и
if(x > Math.Min(y, z()))
Так как Math.Max(y, z())
вернет значение, по крайней мере, такое же, как y, если x < y, тогда нет необходимости оценивать z(), что может занять некоторое время. Аналогичная ситуация с Math.Min
.
Я понимаю, что они могут быть переписаны по строкам
if(x < y || x < z())
для короткого замыкания, но я думаю, что более ясно, что такое сравнение без перезаписи. Это короткое замыкание?
Ответы
Ответ 1
Как отмечали другие, компилятор ничего не знает о семантике 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)))
Ответ 2
Нет, это не короткое замыкание, и z() всегда будет оцениваться. Если вам нужно короткое замыкание, вы должны переписать его, как вы это сделали.
Ответ 3
Math.Min()
и Math.Max()
- это методы, подобные любым другим. Они должны быть оценены, чтобы вернуть значение, которое будет использоваться в качестве второго аргумента в сравнении. Если вы хотите короткое замыкание, вам придется записать условие, используя оператор ||
, как вы показали.
Ответ 4
(Ничего особенного для добавления, но я решил, что поделился результатами теста, на котором я на него набросал.)
Math.Max () может легко быть встроен компилятором CLR "точно в срок", и оттуда мне было любопытно, может ли он еще больше оптимизировать код таким образом, чтобы он был закорочен.
Итак, я взломал микрочип, который оценивает два выражения по 1,000,000 раз каждый.
Для z() я использовал функцию, которая вычисляет Fib (15) с использованием рекурсивного метода. Вот результаты запуска двух:
x < Math.Max(y, z()) : 8097 ms
x < y || x < z() : 29 ms
Я предполагаю, что CLR не преобразует код каким-либо образом, который предотвращает выполнение вызовов метода, потому что он не знает (и не проверяет, есть ли в нем) какие-либо побочные эффекты.
Ответ 5
Нет, это не короткое замыкание, по крайней мере, на уровне компилятора С#. Math.Min
или Math.Max
- это два обычных вызова статических методов, и компилятор не будет оптимизировать в этом смысле.
Порядок оценки кода будет: z(), Math.Max, x > ...
Если вы действительно хотите убедиться, проверьте код IL.