セージ の メモ書き

メモこそ命の恩人だ

C# - 2進数リテラル/ビット演算

2進数リテラル

  • 先頭に "0b" を付与すれば、2進数として表現できる。
  • アンダーバー "_" で値を区切ることもできる。
    • 可読性が向上する。
    • アンダーバーの位置でエラーになることはない。
    • 0b の直後にアンダーバーを挿入できる。
  • C# 7.* 以降で使用できる。
Debug.WriteLine(0b_1);
// 1
Debug.WriteLine(0b_0001);
// 1
Debug.WriteLine(0b_1_0001);
// 17
Debug.WriteLine(0b_1111_1111);
// 255


ビット演算子

docs.microsoft.com

ビット演算子 内容
反転 NOT
論理積 AND
論理和 OR
排他的論理和 XOR
>> 右シフト
<< 左シフト
string GetBinary(int value) => Convert.ToString((byte)value, toBase: 2).PadLeft(8, '0');

// ↓1バイトのデータに対して、ビット演算子を適用する。
byte value = 0b_1111_0000;


Debug.WriteLine($"反転 : {GetBinary(~value)}");
// 反転 : 00001111
// 反転したことを確認。

Debug.WriteLine($"論理積 : {GetBinary(value & 0b_0101_0101)}");
// 論理積 : 01010000
// 0 を適用したビットが 0 になったことを確認。
// 元々 0 の部分は、0 のままであることを確認。

Debug.WriteLine($"論理和 : {GetBinary(value | 0b_0101_0101)}");
// 論理和 : 11110101
// 1 を適用したビットが 1 になったことを確認。
// 元々 1 の部分は、1 のままであることを確認。

Debug.WriteLine($"排他的論理和 : {GetBinary(value ^ 0b_0101_0101)}");
// 排他的論理和 : 10100101
// 0 と 1 の場合、1 になることを確認。
// 同じ値の場合、0 になることを確認。

Debug.WriteLine($"右シフト 1bit : {GetBinary(value >> 1)}");
// 右シフト 1bit : 01111000
// 右に1bit分シフトしたことを確認。シフト後、最上位ビットは 0 になった。

Debug.WriteLine($"右シフト 2bit : {GetBinary(value >> 2)}");
// 右シフト 2bit : 00111100
// 右に2bit分シフトしたことを確認。

Debug.WriteLine($"左シフト 1bit : {GetBinary(value << 1)}");
// 左シフト 1bit : 11100000
// 左に1bit分シフトしたことを確認。

Debug.WriteLine($"左シフト 2bit : {GetBinary(value << 2)}");
// 左シフト 2bit : 11000000
// 左に2bit分シフトしたことを確認。


活用例

指定位置のビット状態をOFF

string GetBinary(int value) => Convert.ToString((byte)value, toBase: 2).PadLeft(8, '0');

int OffBit(int value, int position = 0) 
{
    // 指定位置のビットのみ 1、残りは 0 のデータ。
    var filter = ~(1 << position);
    
    // 論理積で指定位置を強制的に 0 にできる。
    return value & filter;
}

byte value = 0b_0000_0101;

Debug.WriteLine(GetBinary(OffBit(value, position: 0)));
//00000100
Debug.WriteLine(GetBinary(OffBit(value, position: 1)));
//00000101
Debug.WriteLine(GetBinary(OffBit(value, position: 2)));
//00000001

指定位置のビット状態をON

string GetBinary(int value) => Convert.ToString((byte)value, toBase: 2).PadLeft(8, '0');

int OnBit(int value, int position = 0) 
{
    // 指定位置のビットのみ 1、残りは 0 のデータ。
    var filter = 1 << position;

    // 論理和で指定位置を強制的に 1 にできる。
    return value | filter;
}

byte value = 0b_0000_0101;

Debug.WriteLine(GetBinary(OnBit(value, position:0)));
//00000101
Debug.WriteLine(GetBinary(OnBit(value, position: 1)));
//00000111
Debug.WriteLine(GetBinary(OnBit(value, position: 7)));
//10000101

指定位置のビット状態を取得

bool IsOnBit(int value, int position = 0) 
{
    // position は 0スタート。
    // 指定位置のビットのみ 1、残りは 0 のデータ。
    var filter = 1 << position;

    // ↑指定位置以外は全て 0 なので、これで論理積すれば、指定位置の状態が判断できる。
    // 結果が 0 なら、指定位置のビットが 0 である。
    // 結果が 0 以外なら、指定位置のビットが 1 である。
    return (value & filter) != 0;
}

byte value = 0b_0000_0101;

Debug.WriteLine(IsOnBit(value, position: 0));
// True
Debug.WriteLine(IsOnBit(value, position: 1));
// False
Debug.WriteLine(IsOnBit(value, position: 2));
// True

// 指定位置の状態を判定できた。



以上