WisdomSoft - for your serial experiences.

論理演算子

整数のビット列に対して論理積 AND、論理和 OR、排他的論理和 XOR、否定 NOT などを求める演算子を解説します。

ビット列を比較する

プログラムで詳細にビットを操作する場合は、算術演算子ではなく、ビット単位で演算する論理演算子(Logical operators)を使用します。

論理積

論理積 AND は 2 つのビットを比較し、双方が共に 1 であれば 1 を、一方でも 0 であれば 0 を出力する操作です。

図1 論理積
論理積

C# では & 記号であらわされる論理積演算子(Logical AND operator)を用いて 2 つの項を論理積で評価します。通常、論理演算には整数またはブール型を指定します。

整数の場合、ビットの各桁ごとに図1の論理積演算を行った結果を返します。

コード1
class Test
{
	static void Main()
	{
		System.Console.WriteLine(0x0C & 0x0A);
	}
}
実行結果
コード1 実行結果

コード1は整数の論理積演算を行い、その結果を表示しています。整数による論理積演算のことをビットごとの論理積(Integer Bitwise AND)とも呼びます。

図2 ビットごとの論理積演算
ビットごとの論理積演算

図2のように、ビットごとの論理積では、項に指定された 2 つの整数をビット列として考え、各ビットの桁ごとに図1の計算を行います。双方のビットが 1 の場合のみ 1 が出力され、そうでなければ 0 が出力されています。

論理積演算子はブール型でも演算できます。ブール型の場合、双方の項が true の場合は true、そうでなければ false という結果が得られます。

コード2
class Test
{
	static void Main()
	{
		System.Console.WriteLine(true & true);
		System.Console.WriteLine(true & false);
		System.Console.WriteLine(false & true);
		System.Console.WriteLine(false & false);
	}
}
実行結果
コード2 実行結果

コード2はブール型の論理積を計算しています。実行結果のように、双方の項が true の場合のみ true という結果が得られ、そうでなければ false となります。

論理和

論理和 OR は 2 つのビットを比較し、一方でも 1 ならば 1 を出力します。 逆に、双方が 0 の時のみ 0 を出力するとも説明できます。

図3 論理和
論理和

論理和を求めるには | 記号で表される論理和演算子(Logical OR operator)を用います。論理積と同様に、整数を指定することでビットごとの論理和(Integer Bitwise AND)を求めることができます。

コード3
class Test
{
	static void Main()
	{
		System.Console.WriteLine(0x0C | 0x0A);
	}
}
実行結果
コード3 実行結果

コード3コード1と同じ値で論理和を求めたものです。

図4 ビットごとの論理和演算
ビットごとの論理積演算

ビット列のどちらか一方が 1 であれば結果は 1 となるため、図4のような計算となって結果は 10 進数で 14 となります。

論理和演算子にブール型を指定すると、項のどちから一方でも true であれば true が得られます。双方の値が false の場合のみ false が返されます。

コード4
class Test
{
	static void Main()
	{
		System.Console.WriteLine(true | true);
		System.Console.WriteLine(true | false);
		System.Console.WriteLine(false | true);
		System.Console.WriteLine(false | false);
	}
}
実行結果
コード4 実行結果

コード4はブール型の論理和を求め、その結果を出力しています。

排他的論理和

排他的論理和 XOR は、双方のビットが同じ場合は 0、異なる場合は 1 を出力します。 すなわちビットが互いに排他的であれば 1 となる論理演算です。

図5 排他的論理和
排他的論理和

排他的論理和を求めるには ^ 記号による排他的論理和演算子(Logical XOR operator)を使います。これも論理積と同様に、整数を指定することでビットごとの排他的論理和(Integer Bitwise XOR)を求めることができます。

コード5
class Test
{
	static void Main()
	{
		System.Console.WriteLine(0x0C ^ 0x0A);
	}
}
実行結果
コード5 実行結果

コード5コード1と同じ値で排他的論理和を求めたものです。

図6 ビットごとの論理和演算
ビットごとの論理積演算

ビット列のどちらか一方が 1、他方が 0 であれば結果は 1 となるため、図6のような計算となって結果は 10 進数で 6 となります。

排他的論理和演算子にブール型を指定すると、項のどちから一方が true、他方が false であれば true が得られます。双方の値が true または false であれば false が返されます。

コード6
class Test
{
	static void Main()
	{
		System.Console.WriteLine(true ^ true);
		System.Console.WriteLine(true ^ false);
		System.Console.WriteLine(false ^ true);
		System.Console.WriteLine(false ^ false);
	}
}
実行結果
コード6 実行結果

コード6はブール型の排他的論理和を求め、その結果を出力しています。 

ビットごとの補数演算子と論理否定

一般に、入力ビットを反転させる操作を論理否定 NOT と呼びます。すなわち 1 であれば 0 を、0 であれば 1 を返すような処理です。論理否定は入力が 1 つの値しかないので、単項演算子に分類されます。

論理否定
論理否定

この処理において C# では整数とブール型で異なる演算子を用います。いわゆるビットごとの論理否定を行うには ~ 記号で表すビットごとの補数演算子(Bitwise complement operator)を用います。ビットごとの補数演算子は前置演算子なので、項は ~ 記号の後ろに指定します。

コード7
class Test
{
	static void Main()
	{
		System.Console.WriteLine(~0x0A);
		System.Console.WriteLine(~0xFFFFFFF5);
	}
}
実行結果
コード7 実行結果

コード7は整数からビットごとの補数を取得しています。 0x0A (10進数における 10) のビットを反転させると 32 ビットの整数で上位ビットもすべてが 1 になるため 0xFFFFFFF5 となります。これを 10 進数に変換すると、符号を表す最上位ビットが 1 になるため負数になります。0xFFFFFFF5 を反転させると、元の値である 10 に戻ることが結果から確認できます。

ブール型の値を反転するには ! 記号で表す論理否定演算子(Logical negation operator)を用います。これも前置演算子なので項は記号の後に指定します。

コード8
class Test
{
	static void Main()
	{
		System.Console.WriteLine(! true);
		System.Console.WriteLine(! false);
	}
}
実行結果
コード8 実行結果

ブール型の論理否定は、単純に true を渡せば false が、false を渡せば true が返されます。 

条件論理演算

ブール型に対する論理積と論理和演算の場合、片方の項を調べるだけで結果が確定することがあります。例えば、論理積の場合で一方の項が false の場合、もう一方の項に関わらず結果は false であることが確定します。同様に、論理和の場合は一方の項が true であれば、結果は常に true です。

この場合、もう一方の項の値を評価することは計算コストの無駄になるかもしれません。そこで、一方の項で結果が判断できる場合、もう一方の項との評価と演算を省略する条件論理演算子(Conditional logical operators)が使えます。条件論理演算は、ショートサーキット(short-circuiting)論理演算子とも呼ばれます。

条件論理積演算子は && で表し、条件論理和演算子は || で表します。得られる結果は、通常の論理演算子と同じです。多くの場合、ブール型の論理演算には条件論理演算子が使われます。

コード9
class Test
{
	static void Main()
	{
		System.Console.WriteLine(true && true);
		System.Console.WriteLine(true && false);
		System.Console.WriteLine(false && true);
		System.Console.WriteLine(false && false);

		System.Console.WriteLine("-----");

		System.Console.WriteLine(true || true);
		System.Console.WriteLine(true || false);
		System.Console.WriteLine(false || true);
		System.Console.WriteLine(false || false);
	}
}
実行結果
コード9 実行結果

コード9の実行結果は、通常の論理演算と同じです。コード2コード4と同じであることが確認できます。異なるのは、場合によっては右項が計算されない可能性があるという点だけです。

上記の例だけでは効果が明確ではありませんが、例えば (a < b) && (c == d) のような式であれば、a < b が false のとき c == d の計算が行われないということになります。もし、右項の式が何らかの副作用(データの変更などを含む式など)を及ぼす場合、条件論理演算で実行が省略される可能性を考慮しなければなりません。