ほとんどの作業を C と C++ で行っていた当時は、当然のことながら、deMorgan の定理を手動で適用して、重要なブール式を最適化していました。
C# でこれを行うと便利ですか、それともオプティマイザーはこれを不要にしますか?
ほとんどの作業を C と C++ で行っていた当時は、当然のことながら、deMorgan の定理を手動で適用して、重要なブール式を最適化していました。
C# でこれを行うと便利ですか、それともオプティマイザーはこれを不要にしますか?
これほど高速なプロセッサでは、ブール式を並べ替えて実際に速度を変えることは事実上不可能です。また、C# コンパイラは非常にスマートで、最適化も行います。読みやすさと明確さのために最適化してください!
最初の目標は、開発者の理解と保守の容易さのために、そのようなステートメントを最適化することです。
DeMorgan の定理は、このための便利なツールになる可能性があります。
この質問に対する正解は、コンパイラが(通常は)ブール評価を最適化しないということだと思います。たとえば、論理的な短絡が原因です。
if (GetFlagA() || GetFlagB())
{
...do something
}
GetFlagAを呼び出すと、GetFlagBが依存するものが変更される場合、評価の順序が非常に重要になります(これは本当に悪いコードプラクティスですが、別のスレッドでは別のトピックです)。ここでの問題は、GetFlagAが実行され、 trueを返すと、GetFlagBは実行されません。ここで見られるように、GetFlagBの結果は、ステートメントの評価にとって重要ではありません。
A | B | =
F | F | F
F | T | T
T | F | Bの戻り値に関係なくTはtrueです。
T | T | Bの戻り値に関係なくTはtrueです。
要約すると、ド・モルガンの法則などを使用して最適化できるかどうかを尋ねるのは、他のコンピューターサイエンスやソフトウェアエンジニアリングとまったく同じです。"場合によります。" 非機能評価を使用している場合は、おそらく最適化できます。正直なところ、めちゃくちゃ高速なプラットフォームでいくつかの操作について話しているのであれば、ドキュメントの作成に時間を費やしたほうがよいでしょう。
これがお役に立てば幸いです。
The optimization in the JIT, in its current form, does not (from what I've read) optimize this for you. If you need to optimize it, you would need to still take this into account.
That being said, this is a fairly small micro-optimization. In general, I'd prefer to write your "non-trivial boolean expressions" in a more expressive form so they are easier to understand. To me, this is more valuable than any very small optimization you'll get from applying deMorgan's theorem.
コンパイラはすでにそれを行っていると思います。テストを実行し、Reflector を介してコンパイルされた IL を確認できます。
読みやすさと保守性を最適化します。1 年以内に巧妙な最適化を理解できるかどうかを自問してください。コードにコメントを使用できると思われる場合は、コードを自己文書化してください。
再配置、ブール代数またはデモガンを行う必要があるのは、ロジックが複雑すぎて別の方法で実行できない場合だけです。複雑すぎない場合は、読みやすくしてください。ロジックを単純化する場合があります。
ロジックが複雑な場合は、カルノー マップを作成して、ロジックを単純化し、書き留めることができるようにする必要があります。多くの場合、K-Maps を使用すると、ロジックをより簡潔に表現する方法を考え出すのに役立ちます。結果は意味がある場合とそうでない場合がありますが、同等になります。
また、DeMorgan 自体は実際には違いを生む最適化ではないとも言えます。半分以上の項が負 (NOT) の場合、せいぜいいくつかの NOT を削除するパフォーマンスしか得られません。 NOT ごとの CPU の命令。最悪の場合、削除した数だけ NOT を追加できます。DeMorgan を使用する必要がなければ、最初に持っていたよりも多くの NOT を取得することになります。
ロジックを最適化する場合は、ブール代数または私のお気に入りのK-Mapsを使用して、項の数を減らします (可能な場合)。ブール演算子を移動するだけではいけません。ばかげています。
短絡評価が存在する場合、DeMorgan 自体はまったく無関係である可能性があります。
return !(exp1 || exp2);
return !exp1 && !exp2;
にコンパイルする
if( exp1 ) return !(true); else return !(exp2);
if(!(!exp1)) return false; else return !(exp2);
s がキャンセルされ、定数が折りたたまれてnot
いる場合、これらは同一です。
より重要なケースは評価の順序です。式の前に短絡を引き起こす可能性が高い安っぽいものを置きます。副作用などのセマンティックな問題を検出するのが難しいため、または後の式が前の式に基づいて仮定を行う場合、コンパイラはこれを最適化できません。
return validState() && checkAssumuingValidState();
読みやすさとメンテナンスを考慮してください。読むのが難しいかなり複雑なブール式のセットがある場合、DeMorgan の定理は式を読みやすく維持しやすいものに減らすための優れたアプローチかもしれませんが、それでも元の式とは有効/一貫性があります。
一方、より冗長な式の方がはるかに読みやすく、式を減らすと、論理的には同等ですが、理解が難しくなる場合は、そのままにしておきます。
In almost all practical cases I can think of, the arrangement of boolean operators has no noticeable effect on the overall performance. If your program waits for the database, the network etc. it will spend by far more time there than in those tiny operations. Should you write a program where it really makes a difference, better skip C# and use C++ instead.
最近のブール式の最適化に関しては、読みやすさと保守性が最も重要であるという一般的な声明に同意します。したがって、ド・モルガンの定理は一般的に非常に有用です。
この規則には1つの例外があります。ブール式がドモルガンの定理最適化式を変更する場合、維持するのがより困難になる可能性があります。いくつかのブール条件のみを表示するように最適化された、いくつかの入力を持つ式について考えてみます。必要なブール論理への1つの変更により、誰かが可能なすべてのブールの組み合わせを再度リストしてから再最適化する必要がある場合があります。式が最適化されていない形式のままになっていると、変更を完了するために必要な手順が少なくなります。
もっと逸話的な観点から、ド・モルガンの定理やカルノー図などについてチームを教育することで、不必要で非効率的なブール式を減らすことができるのではないかと思います。おそらく、誰かがこれらの方法をよく理解していれば、彼/彼女はより良い表現を生み出す傾向があります。たとえば、最近、私が保守しているソフトウェアのコードでこのブール式に出くわしました。
if ({boolean variable} != true && false)
ド・モルガンの法則は、それを通常形、たとえば選言標準形(DNF)または連言標準形(CNF)に縮小するのに役立ちます。基本的にこれはそれがどちらかであることを意味します
DNF:(aとbとc)OR(eとfとg)..。
また
CNF:(aまたはbまたはc)AND(eまたはfまたはg)...。
あなたは最低レベルでNOTを投げることができます。
私は、読みやすさと理解のために最適化する必要があるという以前のポスターに同意します。
すべての非 CS 専攻者向け:
ド・モルガンの法則は、論理演算子「and」と「or」を否定によって相互に関連付ける規則です。つまり、次のようになります。
NOT (P OR Q) = (NOT P) AND (NOT Q)
NOT (P AND Q) = (NOT P) OR (NOT Q)
最初に保守性と高レベルの最適化に対処します。
次に、低レベルの最適化に対処します。