C# のビット演算

C# の 2 進数表記

C# では 2 進数の数値のリテラルには、接頭辞 0b を付けます。

例えば 10進数の 5 は 2 進数で 101 ですが、これを C# のコード内で記述するには、 0b101 とします。

次の例では 2 進数 0b101 を変数 x にセットし、 その 10進数の値とビット列を表示しています。

using System;

class Program
{
  static void Main(string[] args)
  {
    int x = 0b101;
    Console.WriteLine($"{x}: {Bin(x)}");
    // 5: 00000000000000000000000000000101
  }

  static string Bin(int x)
  {
    var s = Convert.ToString(x, toBase: 2);
    return s = s.PadLeft(sizeof(int) * 8, '0');
  }
}

ビット列を文字列で表示するために、 Convert.ToString() メソッドを利用しています。 toBase: 2 を指定することで 2 進数の表記として文字列を取得できます。

C# のビット演算は int 型 (System.Int32) に対して定義されています。 byte などの他の型で使う場合はキャストして使います。

C# の NOT 演算 (補数演算)

C# での NOT 演算子は単項演算子の ~ です。 NOT 演算 (論理否定) は数値の各ビットに対して、1 は 0 にし、 0 は 1 にします。

ビットを反転させた NOT は元の数の補数といいます。このため ~ は補数演算子 (complement operator) ともいいます。

次の例では元の数値 x の NOT 演算 ~xy にセットしています。

int x = 0b1010100;
int y = ~x;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"y:{Bin(y)}");
// x:00000000000000000000000001010100
// ----------------------------------
// y:11111111111111111111111110101011

y では x のビットが全て反転していることがわかります。

C# の OR 演算

C# での OR 演算子は | です。

OR 演算では二つのビット列で桁ごとにビット値を比較して、いずれかが 1 であれば 1、 両方とも 0 の場合に 0 とします。

int x = 0b101100;
int y = 0b011001;
int z = x | y;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine($"y:{Bin(y)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"z:{Bin(z)}");
// x:00000000000000000000000000101100
// y:00000000000000000000000000011001
// ----------------------------------
// z:00000000000000000000000000111101

C# の XOR 演算

C# での XOR 演算子は ^ です。

XOR 演算では二つのビット列で桁ごとにビット値を比較して、いずれかが 1 であれば 1、 両方とも同じ値の場合に 0 とします。

int x = 0b101100;
int y = 0b011001;
int z = x ^ y;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine($"y:{Bin(y)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"z:{Bin(z)}");
// x:00000000000000000000000000101100
// y:00000000000000000000000000011001
// ----------------------------------
// z:00000000000000000000000000110101

XOR 演算は、特にフラグをゼロクリアする場合などによく使われます。同じフラグに対して XOR 演算を行えば常に 0 になります。

int x = 0b101100;
int z = x ^ x;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"z:{Bin(z)}");
// x:00000000000000000000000000101100
// ----------------------------------
// z:00000000000000000000000000000000

C# の AND 演算

C# での AND 演算子は & です。

AND 演算では二つのビット列で桁ごとにビット値を比較して、両方が 1 の場合に 1 とし、 それ以外は 0 とします。

int x = 0b101110;
int y = 0b011011;
int z = x & y;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine($"y:{Bin(y)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"z:{Bin(z)}");
// x:00000000000000000000000000101110
// y:00000000000000000000000000011011
// ----------------------------------
// z:00000000000000000000000000001010

C# のシフト演算

C# の左シフト演算子は <<、 右シフト演算子は >> です。

変数 演算子 シフト数 (例: x << 3) の形式でシフトする数を指定し、ビット列を右または左にシフトします。

int x = 0b1010100;
int y = x << 3;
Console.WriteLine($"x:{Bin(x)}");
Console.WriteLine("".PadLeft(34, '-'));
Console.WriteLine($"y:{Bin(y)}");
// x:00000000000000000000000001010100
// ----------------------------------
// y:00000000000000000000001010100000

シフト元が存在しない場合はゼロで埋められます。

上の例では左に 3 ビットシフトしています。シフト後の右端 3 ビットはゼロで埋められています。

シフト演算は 2 の累乗数で掛け算 (左シフトの場合) または割り算 (右シフトの場合) を行う場合などに使われます。

左に 1 ビットシフトすると 2 を掛け算した数値になります。 n ビットシフトすると 2 の n 乗を掛け算した数値になります。

int x = 3, y = 0;
Console.WriteLine($"{x,2}: {Bin(x)}");
y = x << 1; // 3 * 2^1
Console.WriteLine($"{y,2}: {Bin(y)}");
y = y << 1; // 3 * 2^2
Console.WriteLine($"{y,2}: {Bin(y)}");
y = y << 1; // 3 * 2^3
Console.WriteLine($"{y,2}: {Bin(y)}");
// 3: 00000000000000000000000000000011
// 6: 00000000000000000000000000000110
//12: 00000000000000000000000000001100
//24: 00000000000000000000000000011000

同様に右に n ビットシフトすると、2 の n 乗で割り算した数値になります。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 C# 入門