Полезно ли в С# применять теорему ДеМоргана для ручной оптимизации булевых выражений в условных операторах (например, если условия)

В тот день, когда я сделал большую часть своей работы на C и С++, я, конечно, вручную применил теорему deMorgan для оптимизации любых нетривиальных булевых выражений.

Полезно ли это сделать на С# или оптимизатор делает это ненужным?

Ответ 1

На процессорах это быстро, практически невозможно переупорядочить булевы выражения, чтобы сделать реальную разницу в скорости. И компилятор С# очень умный, он также оптимизирует его. Оптимизируйте для удобочитаемости и ясности!

Ответ 2

Ваша первая цель должна состоять в том, чтобы оптимизировать такие заявления для понимания разработчика и простоты обслуживания.

Теорема DeMorgan может быть полезным инструментом для этого.

Ответ 3

Оптимизация в JIT в его текущей форме не (из того, что я прочитал) оптимизирует это для вас. Если вам нужно его оптимизировать, вам нужно будет все это учитывать.

Таким образом, это довольно небольшая микро-оптимизация. В общем, я бы предпочел написать ваши "нетривиальные булевы выражения" в более выразительной форме, чтобы их было легче понять. Для меня это более ценно, чем любая небольшая оптимизация, которую вы получите от применения теоремы deMorgan.

Ответ 4

Я считаю, что правильный ответ на этот вопрос заключается в том, что компилятор не (обычно) оптимизирует логические оценки, просто из-за логического короткого замыкания, например:

if (GetFlagA() || GetFlagB())
{
   ...do something
}

Порядок этого, если оценка действительно имеет значение, если вызов GetFlagA изменяет то, на что полагается GetFlagB (если это ДЕЙСТВИТЕЛЬНО неправильная практика кода, но это другая тема для другого потока.) Проблема здесь в логическом коротком замыкании, если GetFlagA запускает и возвращает true, GetFlagB никогда не будет работать, как видно из результатов GetFlagB, несущественно для оценки утверждения.

A | B | =

F | F | F

F | T | Т

T | F | T истинно, независимо от B возвращает val.

T | T | T истинно, независимо от B возвращает val.

Итак, в резюме, спрашивая, можете ли вы оптимизировать с помощью Demorgan или что-то действительно так же, как и остальная компьютерная наука и разработка программного обеспечения. "Это зависит." если вы используете нефункциональную оценку, ее можно оптимизировать. Честно говоря, вы говорите о нескольких операциях на безумно быстрой платформе, вам лучше потратить время на составление документации.

Надеюсь, это поможет.

Ответ 5

Я думаю, что компилятор уже это сделает. Вы можете выполнить тест и посмотреть на скомпилированный IL через Reflector.

Оптимизация для удобства чтения и обслуживания. Спросите себя, если вы поймете свою умную оптимизацию в течение года, и, если вы думаете, код может использовать некоторые комментарии, сделайте сам документирование кода.

Ответ 6

Единственный раз, когда вам нужно перестраивать, булевая алгебра или демонергия - это когда логика слишком сложна, чтобы сделать это по-другому. Если он не слишком сложный, сохраните его для чтения. Существует пример упрощения логики.

Иногда, когда логика сложна, мне нужно создать карту Карно, чтобы упростить логику до того, что я могу даже записать. Часто использование K-Maps может помочь вам придумать более сжатые способы выражения вашей логики. Результат может быть или не иметь смысла, но он будет эквивалентен.

И я бы также сказал, что сам DeMorgan действительно не оптимизация, которая будет иметь значение. Если более половины терминов отрицательны (NOT), вы в лучшем случае получите производительность удаления нескольких NOT, которые представляет собой единую инструкцию для ЦП на НЕ. В худшем случае вы можете добавить столько ННО, сколько вы уберете, и если вы не должны использовать DeMorgan, вы получите больше NOT, чем вы имели в первую очередь.

Если вы собираетесь оптимизировать логику, используйте некоторую логическую алгебру или мой личный любимый K-Maps, чтобы уменьшить количество терминов (если возможно). Не просто двигайте булевы операторы, это глупо.

Ответ 7

Так как оценка булевых выражений использует семантику ярлыков, вы можете перемещать подвыражения, которые дешевле вычислять на фронт:

if (CountAllFilesOnDrive('C:\') > 7 && useFileScan) { ... }

будет запускать дорогостоящий вызов в любое время, пока экспрессия будет оценена, даже если она не нужна. Оборачиваясь, этот оператор пропускает проверку файла, если useFileScan имеет значение false:

if (useFileScan && CountAllFilesOnDrive('C:\') > 7) { ... }

DeMorgan может помочь вам переместить "ранние выходы" на передний план и, таким образом, получить более высокую среднюю производительность.

Обратите внимание, что из-за гарантии оценки слева направо оптимизатор не имеет большой свободы для изменения выражения.

Ответ 8

Учитывайте читаемость и техническое обслуживание. Если у вас довольно сложный набор булевых выражений, которые трудно читать, Deormar может быть отличным подходом к сокращению выражения для чего-то более легкого для чтения/поддержки, но это все еще актуально/согласуется с оригинальным выражением.

Если, с другой стороны, более подробное выражение гораздо легче читать и уменьшать выражение, а логически эквивалентное, затрудняет его понимание, оставьте его как есть.

Ответ 9

Почти во всех практических случаях, о которых я могу думать, расположение булевых операторов не оказывает заметного влияния на общую производительность. Если ваша программа ждет базы данных, сети и т.д., Она будет тратить гораздо больше времени, чем в этих крошечных операциях. Если вы пишете программу, где это действительно имеет значение, лучше пропустите С# и вместо этого используйте С++.

Ответ 10

DeMorgan сам по себе может быть совершенно неактуальен при наличии оценки короткого замыкания.

return !(exp1 || exp2);
return !exp1 && !exp2;

скомпилировать в

if(   exp1 ) return !(true); else return !(exp2);
if(!(!exp1)) return   false; else return !(exp2);

с отменой not и сложенными константами, они идентичны.

Более важным является порядок оценки; поместите cheep вещи, которые, вероятно, вызовут короткие замыкания в начале выражений. Компилятор не может оптимизировать это для вас, потому что ему трудно обнаружить семантические проблемы, такие как побочные эффекты, или если позднее выражение делает предположения на основе более ранних:

return validState() && checkAssumuingValidState();

Ответ 11

Я согласен с общими утверждениями о том, что читаемость и ремонтопригодность наиболее важны, когда речь идет об оптимизации булевых выражений в наши дни. Поэтому теорема ДеМоргана, как правило, очень полезна.

Есть одно исключение из этого правила. Если логическое выражение изменяет выражение, оптимизированное теоремой Demorgan, это может быть труднее поддерживать. Рассмотрим выражение с несколькими входами, которые были оптимизированы для отображения только нескольких логических условий. Одно изменение требуемой логической логики может заставить кого-то снова перечислить все возможные логические комбинации, а затем повторно опробовать. Если бы выражение оставалось в неоптимизированном формате, изменение потребовало бы меньших шагов для завершения.

Больше из анекдотического взгляда, интересно, просветила ли команда команду о теореме ДеМоргана и Карне Карне и т.д. уменьшила бы ненужные/неэффективные булевы выражения. Возможно, если кто-то хорошо разбирается в этих методах, он будет иметь тенденцию выражать более выраженные выражения. Например, я недавно встретил это логическое выражение в коде программного обеспечения, которое я поддерживаю:

if ({boolean variable} != true && false)

Ответ 12

Оптимизатор С# не может действительно сделать слишком много, учитывая правила короткого замыкания для оценки логического выражения. Поэтому применение закона DeMorgan не будет делать многого, если оно не позволит вам увидеть другие полезные рефакторинги (и, конечно же, это поможет сделать код более понятным).

Но есть случаи, когда вы можете значительно повысить производительность с помощью других видов оптимизации выражений. Например, эти условия должны быть заменены

if ( costly_boolean_function() && cheap_often_false_boolean_function() )

Оптимизаторы SQL-запросов делают это, как само собой разумеющееся, поскольку SQL не имеет короткого замыкания. Оптимизатор запросов будет агрессивно перестраивать конъюнктурные предложения WHERE (формы c1 AND c2 AND ... cn), чтобы сначала поставить наименее дорогостоящие условия, так как они могут оценивать значение false и устранять необходимость оценки более дорогих.

Ответ 14

Для всех нас не-CS-майоров:

википедия в законах Де Моргана:

Законы Де Моргана - это правила, касающиеся логические операторы "и" и "или" в терминах друг друга посредством отрицания, а именно:

НЕ (P ИЛИ Q) = (НЕ П) И (НЕ Q)
НЕ (P И Q) = (НЕ P) ИЛИ (НЕ Q)

Ответ 15

Закон Де Моргана полезен для его снижения до нормальной формы, например. Дизъюнктивная нормальная форма (DNF) или конъюнктивная нормальная форма (CNF). В основном это означает, что он либо

DNF: (a и b и c) OR (e и f и g)...

или

CNF: (a или b или c) AND (e или f или g)....

Вы можете выбросить NOT на самом низком уровне.

Я согласен с предыдущими плакатами, которые вы должны оптимизировать для удобочитаемости и понимания.