.net column
.NET開発者のためのブログメディア

Azure障害

C#の<<は?複数・シフト・論理AND・論理排他的OR・論理OR演算子の優先順位とビット演算の実用性

 
SE
C#のビット演算についてくわしく教えてください。
PM
わかりました。それでは、C#のビット演算について解説いたしましょう。

C#の<<とは?


C#で使用する<<はビット演算に利用するものです。そもそもビット演算とは何なのでしょうか。人間は10進数を使いますが、コンピューターは実は2進数しか理解できません。10010110…のように、0と1だけの数字でしか処理できないのです。

ただしC#などのプログラム上では2進数を10進数や16進数に変換して扱っています。それなら2進数については知らなくて良いのでしょうか。決してそうではありません。

コンピュータは2進数で動作するため、2進数で計算すると処理が高速になったり、0か1のフラグを省メモリで持てると言ったメリットがあります。

<<はビット演算で使う演算子

そういった2進数の演算をすることをビット演算と言います。そして<<はそのビット演算をするための演算子なのです。<<の他にも>>などがあります。この記事ではC#で演算子を使うビット演算の方法を紹介しましょう。

では早速<<について解説します。<<は正式な名前は左シフト演算子と言います。以下のC#サンプルをご覧ください。

uint i = 0b0001;
i = i << 1;
Console.WriteLine(i+” “+Convert.ToString(i, 2));

左シフト演算子の実例

uintとはunsigned intのことで、正の数の整数の型です。2進数ではこの型を使うとわかりやすくなります。0b0001の0bとは2進数を記述する場合のルールで、C#では先頭に0bを付けることで2進数を扱えます。

次のi = i << 1;で、iを左に1ビットシフトしています。Convert.ToString(i, 2)はiを2進数の文字列に変換します。実行すると、

2 10

と表示されます。左が10進数表記、右が2進数表記です。10進数と2進数の関係は以下のようになります。2進数は0と1しか使えないので、どんどん桁が上がっていきます。

0 0
1 1
2 10
3 11
4 100
5 101
6 110
7 111
8 1000

<<についての応用

<<は以下の様に<<=という記述もできます。以下のサンプルでは左に2ビットシフトしています。

uint i = 0b0001;
i <<= 2;
Console.WriteLine(i+” “+Convert.ToString(i, 2));

実行結果は、

4 100

になります。このように<<は2進数で桁を繰り上げる動作をします。ここで気づいた人もいると思いますが、左に1ビットシフトするのは、以下と同じです。

i *= 2;

つまり1ビット左にシフトする、とは、2を掛ける・2倍することと同じなのです。

右シフト演算子について

次は右シフト演算子の>>を解説しましょう。ここまで読んでいれば>>の動作は予想がつきますね。以下のC#サンプルをご覧ください。

uint i = 0b0100;
i >>= 1;
Console.WriteLine(i+” “+Convert.ToString(i, 2));

実行結果は、

2 10

になります。100(4)が1つ右シフトして10(2)になりました。>>=1することは/=と同じ、つまり2で割ることと同じになります。

論理AND演算子について

他のビット演算で使われる演算子も紹介します。まずは論理AND演算子です。以下のC#サンプルをご覧下さい。

uint i1 = 0b0101;
uint i2 = 0b1100;
Console.WriteLine(Convert.ToString(i1 & i2, 2));

i1とi2の間の&が論理AND演算子です。この結果は、

100

となります。つまり0100ですね。&は2進数の各桁で掛け算を行います。このサンプルの場合、上の桁から

0x1=0
1×1=1
0x0=0
1×0=0

により、0100となるのです。

論理OR演算子について

他によく使われるのは論理OR演算子です。上のC#サンプルの&を以下のように|に変えてみましょう。

uint i1 = 0b0101;
uint i2 = 0b1100;
Console.WriteLine(Convert.ToString(i1 | i2, 2));

実行結果は、

1101

になります。|は&と違い、各桁の加算を行います。ただし1と1を加算した場合は1のままです。このサンプルでは上の桁から、

0+1=1
1+1=1
0+0=0
1+0=1

と演算され、1101となりました。

論理排他的OR演算子について

論理排他的OR演算子についても紹介します。上のC#サンプルの|を^にしましょう。

uint i1 = 0b0101;
uint i2 = 0b1100;
Console.WriteLine(Convert.ToString(i1 ^ i2, 2));

実行結果は、

1001

となります。^は各桁を比較し、以下のように違う値であれば1、同じであれば0にします。

0と1 1
1と1 0
0と0 0
1と0 1

なお論理排他的OR演算子は、XOR演算子とも言われます。

補数演算子について

補数演算子の~について説明しましょう。以下のC#サンプルを実行すると、

uint i = 0b0101;
Console.WriteLine(Convert.ToString(~i, 2));

以下のようになります。

11111111111111111111111111111010

~は1なら0、0なら1のように各桁のビットを反転させる機能があります。5桁目以上が反転して1になっていますが、4桁目までは1010となって0101が反転しているのがわかりますね。

演算子の優先順位

ここまで紹介した演算子の優先順位はどうなっているのでしょうか。以下は優先度の高い順になっています。

補数演算子 ~
シフト演算子 <<と>>
論理AND演算子 &
論理排他的OR演算子 ^
論理OR演算子 |

例えば以下の結果は、

uint i1 = 0b0100;
uint i2 = 0b0010;
Console.WriteLine(Convert.ToString(i1 & i2 << 1, 2));

100になります。i2が先に左シフトされて0100になるので、その後に&でi1と掛け算をして0100となるわけです。

C#におけるビット演算の実用性

<<をはじめとするビット演算子について紹介しましたが、実際にどのように役に立つのでしょうか。先に述べたように演算の高速化やメモリの節約に役立ちます。しかし今のコンピュータではビット演算による高速化や節約は効果が少なく、それほど意味がありません。

昔のコンピュータはメモリが少なく、少しでも高速化やメモリを節約する必要があったので、このようなビット演算が使われていたのです。

ビットフラグの使い方

それでも敢えてC#でビットフラグを使ってみましょう。以下のサンプルをご覧ください。

uint bitflag = 0;

const uint A_FLAG = (1 << 0);
const uint B_FLAG = (1 << 1);
const uint C_FLAG = (1 << 2);

bitflag |= B_FLAG; // Bフラグを立てる

if ((bitflag & B_FLAG) != 0) Console.WriteLine(“Bフラグが立っています。”);

bitflag &= ~B_FLAG; // Bフラグを消す

if ((bitflag & B_FLAG) == 0) Console.WriteLine(“Bフラグが立っていません。”);

ビットフラグはメモリを節約できる

上のC#サンプルでは、bitflagにB_FLAGを|して0100にしています。その後、~で反転したB_FLAGを&で掛け合わせて、B_FLAGの桁を0にしています。このやり方のメリットは、1つの変数で、桁の数だけのフラグを使えることです。

ビットフラグを使わずbool型でフラグ管理をする場合、以下のように沢山の変数が必要になります。ビットフラグは変数が1つだけで済むのでスマートと言えます。

bool a_flag;
bool b_flag;
bool c_flag;

とはいえ、C#を使う環境でビットフラグを使わなければならないほどメモリが不足していることはありえないので、bool型を列挙する方法で問題はありません。実際にC#でビットフラグを使っている人はまずいないでしょう。

SE
今のコンピュータではビット演算による高速化や節約は効果が少なく、それほど意味がないということですが。
PM
確かに最近のパソコンの性能を考えれば、それほど意味はないかもしれませんが、ビット演算のことを理解していれば、コンピュータの仕組みの理解も深まります。

<<の意味を知ればコンピュータの仕組みの理解が深まる

<<やそれに関連するビット演算について解説しましたが、ご理解頂けましたでしょうか。C#で実際にビット演算をする機会は少ないと思いますが、知っておけばコンピュータの仕組みの理解が深まるのは確かでしょう。


.NET分野でのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)

Search

Popular

reccomended

Categories

Tags