ショートサーキット - 短絡評価と完全評価
【 目次 】
ショートサーキット
意識していないプログラマーの方が多いと思うが、ほとんどのプログラミング言語ではif文等で使われる論理演算はショートサーキット(short-circuit evaluation - 短絡評価)になっている。
- 短絡評価 - Wikipedia
短絡評価(たんらくひょうか、英: short-circuit evaluation)または最小評価(さいしょうひょうか、英: minimal evaluation)とは、一部のプログラミング言語での論理演算子の意味論を示す用語であり、演算子の第一引数を評価した段階で式全体の値が定まらない場合のみ第二引数を評価する方式を意味する。例えば、ANDの第一引数を評価した結果が false であれば、式全体は必ず false になるし、ORの第一引数が true であれば、式全体は必ず true になるので、第二引数を評価するまでもない。
何の事かというとC言語の場合でいうと、以下のようなプログラムがあったとする。
リスト1
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> int fa(){ puts("faを実行"); return true; } int fb(){ puts("fbを実行"); return true; } int main(void) { if(fa() || fb()){ puts("条件式が成立"); } else { puts("条件式が不成立"); } return EXIT_SUCCESS; }
実行結果
faを実行 条件式が成立
この実行結果よりわかる事はmain関数のif文により関数faは実行されるが、関数fbは実行されない。
これは何故かというと、faの実行結果によりfaの戻り値Trueが評価されこれにより、次の関数fbの結果いかんにかかわらずif文の条件式の論理演算の結果がTrueになる事が確定してしまうのでこれ以上fbを実行する必要が無いので関数fbの実行は省略される。
fbを実行しない分だけ実行速度は最適化されることになる。
これを短い処理で評価されるという意味で短絡評価(ショートサーキット)という。
実行時間が速くなるというメリットがあるので、ほとんどの言語でこのように条件式に対する評価はショートサーキットが使われる。
上記の例はor条件の例であるが、and条件においても同じ事がいえる。
関数faとfbの戻り値をtrueからfalseに修正して、
リスト2
public class ShortCircuitTest2 { int fa(){ puts("faを実行"); return false; } int fb(){ puts("fbを実行"); return false; } int main(void) { if(fa() && fb()){ puts("条件式が成立"); } else { puts("条件式が不成立"); } return EXIT_SUCCESS; }
実行結果
faを実行 条件式が不成立
完全評価
ショートサーキットに対する対義語には完全ブール評価(完全論理評価もしくは単に完全評価ともいわれている)というものもある。
完全ブール評価をおこなうには、ビット単位の論理演算をおこなう。
リスト1の場合であれば||演算子のかわりに|演算子、リスト2の場合であれば&&演算子のかわりに&演算子を使う事で完全評価をおこなう事ができる。
関数fbを必ず実行させたい場合、リスト1のifの条件式を
if(fa() | fb()){
実行結果
faを実行 fbを実行 条件式が成立
リスト2の場合には
if(fa() & fb()){
実行結果
faを実行 fbを実行 条件式が不成立
ショートサーキットを応用
このショートサーキットの特性を積極的に利用する事で、通常はエラーになるようなコードのエラーを回避できる。
今度はJavaの例であるが、文字列sが空文字かどうかの判定は以下のようなコードがよく使われる。
if(s==null || s.equals("")){ }
もしsがnullだとすると
s.equals("")
を実行するとエラーになってしまうが、短絡評価されるのでエラーにならない。
しかし、もし、あやまって条件式の順序を逆にしてしまうと
String s = null; if(s.equals("") || s==null){ }
ヌルポ(java.lang.NullPointerException)が発生してしまう事になる。
もう一度c言語に戻って、ショートサーキットの特性を使うと条件式だけでif文等とおなじ効果を発揮させる事ができる。
以下のif文は
if (fa()) fb();
ショートサーキットを利用してif無しの以下のコードに置き換える事ができる。
fa() && fb();
これらのテクニックはベテランプログラマーにとっては常識的な事だが、ショートサーキットによる条件式の動作を理解していないと混乱してしまうことになる。
プログラミング言語とショートサーキット
C#やjava等のc言語に似た構文を採用する言語では論理演算子は&や|であるが、他の言語の場合はどうかというと。
pythonの場合は短絡評価の論理演算子にand
とor
そしてビット単位の論理演算子にc言語と同じ&
や|
を使う。
VB.netの場合は基本は完全評価でAnd
とOr
そして短絡評価する場合には特別にAndAlso
とOrElse
を使うようだ。
そしてDelphiのようにコンパイラオプションで短絡評価をするか完全評価をするか選択できる言語もある。
各言語の論理演算子について比較したサイトを見つけたので、以下も参照。