C#・VBでは言語組み込みのビット演算として、AND・ORなどの論理演算やシフトなどの演算子が用意されています。 (§.ビット演算子§.シフト演算子)

このほかに、.NETでは言語組み込みの演算子では直接サポートされない回転シフトなどのようなビット演算を行うためのクラスBitOperationsが用意されています。 (§.BitOperationsクラス)

ここではこれらのビット演算について解説します。 あわせて、ビット演算に際してよく用いられる基数を指定して数値⇄文字列の変換を行う方法についても解説します。 2進数・16進数で数値(整数リテラル)を記述する方法についてはリテラルとサフィックス §.整数リテラルを参照してください。

なお、この文章では、n進法での数値表記であることを強調する場合、下付きの(n)を使用します。 10進数での数値31は31(10)、他の基数の場合も同様に11111(2) = 31(10) = 1F(16)のように表記します。

ビット演算子

C#・VBでは言語組み込みのビットごとの演算として、以下のビット演算子が用意されています。 整数型に対して使用することで、ビットごとの演算を行うことができます。 &=などのように、ビット演算子に=を後置できる演算子では、代入先を左オペランド(左項)とする複合代入演算子となります。

ビット演算子
ビット演算 演算子
C# VB
論理否定(NOT)・1の補数 ~ Not
論理積(AND) &, &= And
論理和(OR) |, |= Or
排他的論理和(XOR) ^, ^= Xor

C#におけるビット演算子は、32ビットまたは64ビットの整数型(int, uint, long, uint)に対してのみ定義されています。 8ビット・16ビット整数型に対してビットごとの演算を行う場合、値は自動的にintへ拡大変換された上で演算が行われます。 つまり、sbyte, byte, char, short, ushortの値に対して演算を行う場合、結果はintとなります。 複合代入演算子を使う場合は、自動的に代入先の型にキャストされます。

NOT・AND・OR・XORの各演算子を使ってビット演算を行う
using System;

static class Sample {
  static void Main()
  {
    int x = 0x55AA_00FF;
    int y = 0x5A5A_0F0F;

    int not_x   = ~x;    // NOT(論理否定)
    int x_or_y  = x | y; // OR(論理和)
    int x_and_y = x & y; // AND(論理積)
    int x_xor_y = x ^ y; // XOR(排他的論理和)

    Console.WriteLine("~{0} = {1}", x.ToBinary(), not_x.ToBinary());
    Console.WriteLine("{0} | {1} = {2}", x.ToBinary(), y.ToBinary(), x_or_y.ToBinary());
    Console.WriteLine("{0} & {1} = {2}", x.ToBinary(), y.ToBinary(), x_and_y.ToBinary());
    Console.WriteLine("{0} ^ {1} = {2}", x.ToBinary(), y.ToBinary(), x_xor_y.ToBinary());

    byte bx = 0x00; // 8ビット整数
    byte by = 0xFF;

    // ビット演算子では8ビット・16ビットの整数型はintに拡大変換した上で演算されるため、
    // 結果を8ビット・16ビットの整数型に代入する場合は明示的にキャストする必要がある
    byte b1 = (byte)~bx;
    byte b2 = (byte)(bx & by);

    bx &= by; // 複合代入演算子の場合はキャストする必要はない
  }

#region "数値を二進数表記の文字列化するためのメソッド"
  static string ToBinary(this int number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(int), '0');
#endregion
}
実行結果
~0b_01010101101010100000000011111111 = 0b_10101010010101011111111100000000
0b_01010101101010100000000011111111 | 0b_01011010010110100000111100001111 = 0b_01011111111110100000111111111111
0b_01010101101010100000000011111111 & 0b_01011010010110100000111100001111 = 0b_01010000000010100000000000001111
0b_01010101101010100000000011111111 ^ 0b_01011010010110100000111100001111 = 0b_00001111111100000000111111110000

VBにおけるビット演算子は、Charを除く各整数型に対して使用できます。 演算の結果は、左右のオペランド(項)が同じ型の場合はその型、異なる型の場合はより大きい型の方に拡大変換されます。

NOT・AND・OR・XORの各演算子を使ってビット演算を行う
Imports System

Module Sample
  Sub Main()
    Dim x As Integer = &H_55AA_00FF
    Dim y As Integer = &H_5A5A_0F0F

    Dim not_x As Integer   = Not x   ' NOT(論理否定)
    Dim x_or_y As Integer  = x Or y  ' OR(論理和)
    Dim x_and_y As Integer = x And y ' AND(論理積)
    Dim x_xor_y As Integer = x Xor y ' XOR(排他的論理和)

    Console.WriteLine("Not {0} = {1}", x.ToBinary(), not_x.ToBinary())
    Console.WriteLine("{0}  Or {1} = {2}", x.ToBinary(), y.ToBinary(), x_or_y.ToBinary())
    Console.WriteLine("{0} And {1} = {2}", x.ToBinary(), y.ToBinary(), x_and_y.ToBinary())
    Console.WriteLine("{0} Xor {1} = {2}", x.ToBinary(), y.ToBinary(), x_xor_y.ToBinary())
  End Sub

#Region "数値を二進数表記の文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As Integer) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
Not &B_01010101101010100000000011111111 = &B_10101010010101011111111100000000
&B_01010101101010100000000011111111  Or &B_01011010010110100000111100001111 = &B_01011111111110100000111111111111
&B_01010101101010100000000011111111 And &B_01011010010110100000111100001111 = &B_01010000000010100000000000001111
&B_01010101101010100000000011111111 Xor &B_01011010010110100000111100001111 = &B_00001111111100000000111111110000

上記の演算子をboolBooleanに対して使用すると、ビットごとの演算ではなく単一のブール値に対する演算を行う論理演算子となります。 ただしVBでは、ブール値に対して論理積・論理和を求める場合は通常AndAlsoOrElse演算子を使います 詳細は論理演算子 §.AndAlso演算子・OrElse演算子を参照してください。

ビット演算子はFlags属性を持つ列挙体に対しても使用することができます。 (列挙体とフラグ)

シフト演算子

C#、およびVB(7.1以降)では、言語組み込みのシフト演算として、以下のシフト演算子が用意されています。 代入先を左オペランド(左項)とする複合代入演算子も用意されています。

シフト演算子
シフト演算 演算子
C# VB(7.1以降)
左シフト <<, <<= <<, <<=
右シフト >>, >>= >>, >>=

右シフト演算子は、左オペランド(左項・シフトされる値)が符号付き整数の場合は算術シフト(負数の場合は上位側ビットに1、正数の場合は0が補われる)となり、符号無し整数の場合は論理シフト(上位側ビットに常に0が補われる)となります。 言い換えると、右シフト演算子では常に最上位ビット(符号ビット)と同じ値が補われます。 左シフト演算子では、常に0が補われます。

C#におけるシフト演算子は、32ビットまたは64ビットの整数型(int, uint, long, uint)に対してのみ定義されています。 8ビット・16ビット整数型に対してシフト演算を行う場合、値は自動的にintへ拡大変換された上でシフト演算が行われます。 つまり、sbyte, byte, char, short, ushortの値に対してシフト演算を行う場合、結果はintとなります。 複合代入演算子を使う場合は、自動的に代入先の型にキャストされます。

右シフト・左シフト演算子を使ってシフト演算を行う
using System;

static class Sample {
  static void Main()
  {
    int x = 1; // 32ビット整数
    Console.WriteLine(x.ToBinary());

    // 左に1ビットシフトする
    x = x << 1;
    Console.WriteLine(x.ToBinary());

    x <<= 1; // 複合代入演算子、動作は上と同じ
    Console.WriteLine(x.ToBinary());

    x = int.MinValue;
    Console.WriteLine(x.ToBinary());

    // 右に1ビットシフトする
    x = x >> 1;
    Console.WriteLine(x.ToBinary());

    x >>= 1; // 複合代入演算子、動作は上と同じ
    Console.WriteLine(x.ToBinary());

    byte b = 1; // 8ビット整数

    // シフト演算では8ビット・16ビットの整数型はintに拡大変換した上で演算されるため、
    // 結果を8ビット・16ビットの整数型に代入する場合は明示的にキャストする必要がある
    b = (byte)(b << 1);
    b <<= 1; // 複合代入演算子の場合はキャストする必要はない

    b = (byte)(b >> 1);
    b >>= 1;
  }

#region "数値を二進数表記の文字列化するためのメソッド"
  static string ToBinary(this int number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(int), '0');
#endregion
}
実行結果
0b_00000000000000000000000000000001
0b_00000000000000000000000000000010
0b_00000000000000000000000000000100
0b_10000000000000000000000000000000
0b_11000000000000000000000000000000
0b_11100000000000000000000000000000

VBにおけるシフト演算子は、Charを除く各整数型に対して使用できます。 シフト演算の結果は、常に左オペランド(シフトされる値)と同じ型となります。

右シフト・左シフト演算子を使ってシフト演算を行う
Imports System

Module Sample
  Sub Main()
    Dim x As Integer = 1 ' 32ビット整数
    Console.WriteLine(x.ToBinary())

    ' 左に1ビットシフトする
    x = x << 1
    Console.WriteLine(x.ToBinary())

    ' 複合代入演算子、動作は上と同じ
    x <<= 1
    Console.WriteLine(x.ToBinary())

    x = Integer.MinValue
    Console.WriteLine(x.ToBinary())

    ' 右に1ビットシフトする
    x = x >> 1
    Console.WriteLine(x.ToBinary())

    x >>= 1 ' 複合代入演算子、動作は上と同じ
    Console.WriteLine(x.ToBinary())
  End Sub

#Region "数値を二進数表記の文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As Integer) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
&B_00000000000000000000000000000001
&B_00000000000000000000000000000010
&B_00000000000000000000000000000100
&B_10000000000000000000000000000000
&B_11000000000000000000000000000000
&B_11100000000000000000000000000000

右オペランド(右項・シフトする量、amount)は、常に左オペランドの型のビット数未満となるようにマスクされます。 例として32ビット整数をシフトしようとする場合、右オペランドの値は31(10)=11111(2)で自動的にマスク(AND演算)されます。 値が32ビット整数でシフト量が33の場合、33(10) AND 31(10) = 1(10)つまりシフト量1のシフト演算となります。

このため、シフト量が型のビット数を超える値となる場合や、特に逆方向へのシフトを意図して負の値を指定してもそのとおりの動作とはならない点には注意が必要です。

右シフト・左シフト演算子では、型のビット数以上のシフト量はマスクされる
using System;

static class Sample {
  static void Main()
  {
    int x = 1; // 32ビット整数

    // 左右シフト演算子では、シフト量(amount)は常に型のビット数未満となるよう自動的にマスクされる
    // 32ビット整数に対して33ビットシフトしようとすると、33 & (32 - 1) = 1ビットのシフトとなる

    // 左シフト演算子の結果を2進数で表示
    Console.WriteLine($"{x.ToBinary()} <<  0 = {( x <<  0 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} <<  1 = {( x <<  1 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} <<  2 = {( x <<  2 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} << 31 = {( x << 31 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} << 32 = {( x << 32 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} << 33 = {( x << 33 ).ToBinary()}");
    Console.WriteLine();

    x = int.MinValue;

    // 右シフト演算子の結果を2進数で表示
    Console.WriteLine($"{x.ToBinary()} >>  0 = {( x >>  0 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} >>  1 = {( x >>  1 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} >>  2 = {( x >>  2 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} >> 31 = {( x >> 31 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} >> 32 = {( x >> 32 ).ToBinary()}");
    Console.WriteLine($"{x.ToBinary()} >> 33 = {( x >> 33 ).ToBinary()}");
    Console.WriteLine();
  }

#region "数値を二進数表記で文字列化するためのメソッド"
  static string ToBinary(this int number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(int), '0');
#endregion
}
実行結果
0b_00000000000000000000000000000001 <<  0 = 0b_00000000000000000000000000000001
0b_00000000000000000000000000000001 <<  1 = 0b_00000000000000000000000000000010
0b_00000000000000000000000000000001 <<  2 = 0b_00000000000000000000000000000100
0b_00000000000000000000000000000001 << 31 = 0b_10000000000000000000000000000000
0b_00000000000000000000000000000001 << 32 = 0b_00000000000000000000000000000001
0b_00000000000000000000000000000001 << 33 = 0b_00000000000000000000000000000010

0b_10000000000000000000000000000000 >>  0 = 0b_10000000000000000000000000000000
0b_10000000000000000000000000000000 >>  1 = 0b_11000000000000000000000000000000
0b_10000000000000000000000000000000 >>  2 = 0b_11100000000000000000000000000000
0b_10000000000000000000000000000000 >> 31 = 0b_11111111111111111111111111111111
0b_10000000000000000000000000000000 >> 32 = 0b_10000000000000000000000000000000
0b_10000000000000000000000000000000 >> 33 = 0b_11000000000000000000000000000000

右シフト・左シフト演算子では、型のビット数以上のシフト量はマスクされる
Imports System

Module Sample
  Sub Main()
    Dim x As Integer = 1 ' 32ビット整数

    ' 左右シフト演算子では、シフト量(amount)は常に型のビット数未満となるよう自動的にマスクされる
    ' 32ビット整数に対して33ビットシフトしようとすると、33 & (32 - 1) = 1ビットのシフトとなる

    ' 左シフト演算子の結果を2進数で表示
    Console.WriteLine($"{x.ToBinary()} <<  0 = {( x <<  0 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} <<  1 = {( x <<  1 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} <<  2 = {( x <<  2 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} << 31 = {( x << 31 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} << 32 = {( x << 32 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} << 33 = {( x << 33 ).ToBinary()}")
    Console.WriteLine()

    x = Integer.MinValue

    ' 右シフト演算子の結果を2進数で表示
    Console.WriteLine($"{x.ToBinary()} >>  0 = {( x >>  0 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} >>  1 = {( x >>  1 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} >>  2 = {( x >>  2 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} >> 31 = {( x >> 31 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} >> 32 = {( x >> 32 ).ToBinary()}")
    Console.WriteLine($"{x.ToBinary()} >> 33 = {( x >> 33 ).ToBinary()}")
    Console.WriteLine()
  End Sub

#Region "数値を二進数表記で文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As Integer) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
&B_00000000000000000000000000000001 <<  0 = &B_00000000000000000000000000000001
&B_00000000000000000000000000000001 <<  1 = &B_00000000000000000000000000000010
&B_00000000000000000000000000000001 <<  2 = &B_00000000000000000000000000000100
&B_00000000000000000000000000000001 << 31 = &B_10000000000000000000000000000000
&B_00000000000000000000000000000001 << 32 = &B_00000000000000000000000000000001
&B_00000000000000000000000000000001 << 33 = &B_00000000000000000000000000000010

&B_10000000000000000000000000000000 >>  0 = &B_10000000000000000000000000000000
&B_10000000000000000000000000000000 >>  1 = &B_11000000000000000000000000000000
&B_10000000000000000000000000000000 >>  2 = &B_11100000000000000000000000000000
&B_10000000000000000000000000000000 >> 31 = &B_11111111111111111111111111111111
&B_10000000000000000000000000000000 >> 32 = &B_10000000000000000000000000000000
&B_10000000000000000000000000000000 >> 33 = &B_11000000000000000000000000000000

回転シフト・循環シフトを行う場合はBitOperations.RotateLeftメソッド・RotateRightメソッドを使用します。 このメソッドでは、シフト量に負の値を指定すると逆方向への回転シフトとなります。

BitOperationsクラス

BitOperationsクラスは、特定CPUに固有な命令に対応するビット演算や、それに類似するビット演算を行うためのクラスです。 CPUがサポートしている場合はベクトル演算が使用されるVector<T>構造体と同様に、JITコンパイラによってメソッド呼び出しが固有のCPU命令、あるいはそれを利用した実装に展開されます。 これにより、BitOperationsクラスにより提供される演算を独自に実装する必要がなくなり、また多用するような場面ではパフォーマンス向上が期待できます。

BitOperationsクラスのメソッドでは、対応するCPU命令がサポートされていない場合でも例外とはならず、同じ結果を返すフォールバック実装(汎用のビット演算・算術演算による実装)が実行されます。 このため、CPUがサポートしているかどうかを呼び出し前に調べる必要はありません。 また、各メソッドはMethodImpl属性MethodImplOptions.AggressiveInliningが指定されているため、メソッド呼び出しはフォールバック実装となる場合でも積極的にインライン展開されるようになっています。

BitOperationsクラスは.NET Core 3.0/.NET 5以降でサポートされます。 .NET Standardでは使用できません。 BitOperationsクラスでは、Mathクラスと同様に静的メソッドとして用意されているメソッドを呼び出します。 インスタンスの作成は不要です。 また、使用に際しては名前空間System.Numericsをインポートします。

左回転シフト・右回転シフト (RotateLeft・RotateRight)

RotateLeftメソッドRotateRightメソッドは、回転シフト(循環シフトcircular shift)を行います。 x86 ROL/ROR命令に類似する演算を行います。

RotateLeft・RotateRightメソッドは、uint/UInteger, ulong/ULongの整数型のみに対して定義されています。 シフト量(引数offset)は、値の型のビット数(32または64)を超える数を指定できるほか、負数を指定することもできます。 シフト量が負の場合は、逆方向への回転シフトになります。

BitOperations.RotateLeft/RotateRightメソッドで左回転シフト・右回転シフトを行う .NET Core 3.0
using System;
using System.Numerics;

static class Sample {
  static void Main()
  {
    // BitOperations.RotateLeft/RotateRightメソッドはuint/ulongに対してのみ使用できる
    uint val = 0b_1000_0000_0000_0000_0000_0000_0000_0001;

    // BitOperations.RotateLeftで値に対して左回転シフトを行う
    uint val_rol1 = BitOperations.RotateLeft(val, 1);

    // BitOperations.RotateRightで値に対して右回転シフトを行う
    uint val_ror1 = BitOperations.RotateRight(val, 1);

    Console.WriteLine($"RotateLeft({val.ToBinary()}, -1) = {BitOperations.RotateLeft(val, -1).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()},  0) = {BitOperations.RotateLeft(val,  0).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()},  1) = {BitOperations.RotateLeft(val,  1).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()},  2) = {BitOperations.RotateLeft(val,  2).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 31) = {BitOperations.RotateLeft(val, 31).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 32) = {BitOperations.RotateLeft(val, 32).ToBinary()}");
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 33) = {BitOperations.RotateLeft(val, 33).ToBinary()}");
    Console.WriteLine();

    Console.WriteLine($"RotateRight({val.ToBinary()}, -1) = {BitOperations.RotateRight(val, -1).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()},  0) = {BitOperations.RotateRight(val,  0).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()},  1) = {BitOperations.RotateRight(val,  1).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()},  2) = {BitOperations.RotateRight(val,  2).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()}, 31) = {BitOperations.RotateRight(val, 31).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()}, 32) = {BitOperations.RotateRight(val, 32).ToBinary()}");
    Console.WriteLine($"RotateRight({val.ToBinary()}, 33) = {BitOperations.RotateRight(val, 33).ToBinary()}");
    Console.WriteLine();
  }

#region "数値を二進数表記で文字列化するためのメソッド"
  static string ToBinary(this uint number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(uint), '0');
#endregion
}
実行結果
RotateLeft(0b_10000000000000000000000000000001, -1) = 0b_11000000000000000000000000000000
RotateLeft(0b_10000000000000000000000000000001,  0) = 0b_10000000000000000000000000000001
RotateLeft(0b_10000000000000000000000000000001,  1) = 0b_00000000000000000000000000000011
RotateLeft(0b_10000000000000000000000000000001,  2) = 0b_00000000000000000000000000000110
RotateLeft(0b_10000000000000000000000000000001, 31) = 0b_11000000000000000000000000000000
RotateLeft(0b_10000000000000000000000000000001, 32) = 0b_10000000000000000000000000000001
RotateLeft(0b_10000000000000000000000000000001, 33) = 0b_00000000000000000000000000000011

RotateRight(0b_10000000000000000000000000000001, -1) = 0b_00000000000000000000000000000011
RotateRight(0b_10000000000000000000000000000001,  0) = 0b_10000000000000000000000000000001
RotateRight(0b_10000000000000000000000000000001,  1) = 0b_11000000000000000000000000000000
RotateRight(0b_10000000000000000000000000000001,  2) = 0b_01100000000000000000000000000000
RotateRight(0b_10000000000000000000000000000001, 31) = 0b_00000000000000000000000000000011
RotateRight(0b_10000000000000000000000000000001, 32) = 0b_10000000000000000000000000000001
RotateRight(0b_10000000000000000000000000000001, 33) = 0b_11000000000000000000000000000000

BitOperations.RotateLeft/RotateRightメソッドで左回転シフト・右回転シフトを行う .NET Core 3.0
Imports System
Imports System.Numerics

Module Sample
  Sub Main()
    ' BitOperations.RotateLeft/RotateRightメソッドはUInteger/ULongに対してのみ使用できる
    Dim val As UInteger = &B_1000_0000_0000_0000_0000_0000_0000_0001UI

    ' BitOperations.RotateLeftで値に対して左回転シフトを行う
    Dim val_rol1 As UInteger = BitOperations.RotateLeft(val, 1)

    ' BitOperations.RotateRightで値に対して右回転シフトを行う
    Dim val_ror1 As UInteger = BitOperations.RotateRight(val, 1)

    Console.WriteLine($"RotateLeft({val.ToBinary()}, -1) = {BitOperations.RotateLeft(val, -1).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()},  0) = {BitOperations.RotateLeft(val,  0).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()},  1) = {BitOperations.RotateLeft(val,  1).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()},  2) = {BitOperations.RotateLeft(val,  2).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 31) = {BitOperations.RotateLeft(val, 31).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 32) = {BitOperations.RotateLeft(val, 32).ToBinary()}")
    Console.WriteLine($"RotateLeft({val.ToBinary()}, 33) = {BitOperations.RotateLeft(val, 33).ToBinary()}")
    Console.WriteLine()

    Console.WriteLine($"RotateRight({val.ToBinary()}, -1) = {BitOperations.RotateRight(val, -1).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()},  0) = {BitOperations.RotateRight(val,  0).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()},  1) = {BitOperations.RotateRight(val,  1).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()},  2) = {BitOperations.RotateRight(val,  2).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()}, 31) = {BitOperations.RotateRight(val, 31).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()}, 32) = {BitOperations.RotateRight(val, 32).ToBinary()}")
    Console.WriteLine($"RotateRight({val.ToBinary()}, 33) = {BitOperations.RotateRight(val, 33).ToBinary()}")
    Console.WriteLine()
  End Sub

#Region "数値を二進数表記で文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As UInteger) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
RotateLeft(&B_10000000000000000000000000000001, -1) = &B_11000000000000000000000000000000
RotateLeft(&B_10000000000000000000000000000001,  0) = &B_10000000000000000000000000000001
RotateLeft(&B_10000000000000000000000000000001,  1) = &B_00000000000000000000000000000011
RotateLeft(&B_10000000000000000000000000000001,  2) = &B_00000000000000000000000000000110
RotateLeft(&B_10000000000000000000000000000001, 31) = &B_11000000000000000000000000000000
RotateLeft(&B_10000000000000000000000000000001, 32) = &B_10000000000000000000000000000001
RotateLeft(&B_10000000000000000000000000000001, 33) = &B_00000000000000000000000000000011

RotateRight(&B_10000000000000000000000000000001, -1) = &B_00000000000000000000000000000011
RotateRight(&B_10000000000000000000000000000001,  0) = &B_10000000000000000000000000000001
RotateRight(&B_10000000000000000000000000000001,  1) = &B_11000000000000000000000000000000
RotateRight(&B_10000000000000000000000000000001,  2) = &B_01100000000000000000000000000000
RotateRight(&B_10000000000000000000000000000001, 31) = &B_00000000000000000000000000000011
RotateRight(&B_10000000000000000000000000000001, 32) = &B_10000000000000000000000000000001
RotateRight(&B_10000000000000000000000000000001, 33) = &B_11000000000000000000000000000000

先行する/後続する0のビット数 (LeadingZeroCount・TrailingZeroCount)

LeadingZeroCountメソッドTrailingZeroCountメソッドは、1のビットに先行/後続する0のビットの数(最上位/最下位ビットから見て0の桁が連続する数)を計上します。 x86 LZCNT/TZCNT命令に類似する演算を行います。

LeadingZeroCount・TrailingZeroCountメソッドは、uint/UInteger, ulong/ULongの整数型のみに対して定義されています。 なお、結果はint/Integerで返されます。

BitOperations.LeadingZeroCount/TrailingZeroCountメソッドで先行/後続する0のビットの数を計上する .NET Core 3.0
using System;
using System.Numerics;

static class Sample {
  static void Main()
  {
    // BitOperations.LeadingZeroCount/TrailingZeroCountメソッドはuint/ulongに対してのみ使用できる
    uint val = 0b_0000_0000_0000_0001_1000_0000_0000_0000;

    // BitOperations.LeadingZeroCountで最上位ビットから連続する0のビットの数を求める
    int lzcnt = BitOperations.LeadingZeroCount(val);

    // BitOperations.TrailingZeroCountで最下位ビットより連続する0のビットの数を求める
    int tzcnt = BitOperations.TrailingZeroCount(val);

    foreach (var amount in new[] {0, 1, 2, 29, 30, 31}) {
      val = 0b_1u << amount;
      lzcnt = BitOperations.LeadingZeroCount(val);

      Console.WriteLine($"LeadingZeroCount({val.ToBinary()}) = {lzcnt}");
    }
    Console.WriteLine();

    foreach (var amount in new[] {0, 1, 2, 29, 30, 31}) {
      val = 0b_1u << (31 - amount);
      tzcnt = BitOperations.TrailingZeroCount(val);

      Console.WriteLine($"TrailingZeroCount({val.ToBinary()}) = {tzcnt}");
    }
    Console.WriteLine();
  }

#region "数値を二進数表記で文字列化するためのメソッド"
  static string ToBinary(this uint number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(uint), '0');
#endregion
}
実行結果
LeadingZeroCount(0b_00000000000000000000000000000001) = 31
LeadingZeroCount(0b_00000000000000000000000000000010) = 30
LeadingZeroCount(0b_00000000000000000000000000000100) = 29
LeadingZeroCount(0b_00100000000000000000000000000000) = 2
LeadingZeroCount(0b_01000000000000000000000000000000) = 1
LeadingZeroCount(0b_10000000000000000000000000000000) = 0

TrailingZeroCount(0b_10000000000000000000000000000000) = 31
TrailingZeroCount(0b_01000000000000000000000000000000) = 30
TrailingZeroCount(0b_00100000000000000000000000000000) = 29
TrailingZeroCount(0b_00000000000000000000000000000100) = 2
TrailingZeroCount(0b_00000000000000000000000000000010) = 1
TrailingZeroCount(0b_00000000000000000000000000000001) = 0

BitOperations.LeadingZeroCount/TrailingZeroCountメソッドで先行/後続する0のビットの数を計上する .NET Core 3.0
Imports System
Imports System.Numerics

Module Sample
  Sub Main()
    ' BitOperations.LeadingZeroCount/TrailingZeroCountメソッドはUInteger/ULongに対してのみ使用できる
    Dim val As UInteger = &B_0000_0000_0000_0001_1000_0000_0000_0000UI

    ' BitOperations.LeadingZeroCountで最上位ビットから連続する0のビットの数を求める
    Dim lzcnt As Integer = BitOperations.LeadingZeroCount(val)

    ' BitOperations.TrailingZeroCountで最下位ビットより連続する0のビットの数を求める
    Dim tzcnt As Integer = BitOperations.TrailingZeroCount(val)

    For Each amount As Integer In New Integer() {0, 1, 2, 29, 30, 31}
      val = &B_1UI << amount
      lzcnt = BitOperations.LeadingZeroCount(val)

      Console.WriteLine($"LeadingZeroCount({val.ToBinary()}) = {lzcnt}")
    Next
    Console.WriteLine()

    For Each amount As Integer In New Integer() {0, 1, 2, 29, 30, 31}
      val = &B_1UI << amount
      tzcnt = BitOperations.TrailingZeroCount(val)

      Console.WriteLine($"TrailingZeroCount({val.ToBinary()}) = {tzcnt}")
    Next
    Console.WriteLine()
  End Sub

#Region "数値を二進数表記で文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As UInteger) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
LeadingZeroCount(&B_00000000000000000000000000000001) = 31
LeadingZeroCount(&B_00000000000000000000000000000010) = 30
LeadingZeroCount(&B_00000000000000000000000000000100) = 29
LeadingZeroCount(&B_00100000000000000000000000000000) = 2
LeadingZeroCount(&B_01000000000000000000000000000000) = 1
LeadingZeroCount(&B_10000000000000000000000000000000) = 0

TrailingZeroCount(&B_00000000000000000000000000000001) = 0
TrailingZeroCount(&B_00000000000000000000000000000010) = 1
TrailingZeroCount(&B_00000000000000000000000000000100) = 2
TrailingZeroCount(&B_00100000000000000000000000000000) = 29
TrailingZeroCount(&B_01000000000000000000000000000000) = 30
TrailingZeroCount(&B_10000000000000000000000000000000) = 31

立っているビットの数 (PopCount)

PopCountメソッドは、立っている(1である)ビットの数(population count)を計上します。 x86 POPCNT命令に類似する演算を行います。

PopCountメソッドは、uint/UInteger, ulong/ULongの整数型のみに対して定義されています。 なお、結果はint/Integerで返されます。

BitOperations.PopCountメソッドで立っているビットの数を計上する .NET Core 3.0
using System;
using System.Numerics;

static class Sample {
  static void Main()
  {
    // BitOperations.PopCountメソッドはuint/ulongに対してのみ使用できる
    uint val = 0b_1111_0000_1010_0000_1000_0100_0010_0001;

    // BitOperations.PopCountで立っているビット(1のビット)の数を求める
    int popcnt = BitOperations.PopCount(val);

    foreach (var _val in new uint[] {0x1u, 0x5u, 0x123u, 0xCAFEu, 0xFFFFFFFEu}) {
      popcnt = BitOperations.PopCount(_val);

      Console.WriteLine($"PopCount({_val.ToBinary()}) = {popcnt}");
    }
  }

#region "数値を二進数表記で文字列化するためのメソッド"
  static string ToBinary(this uint number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(uint), '0');
#endregion
}
実行結果
PopCount(0b_00000000000000000000000000000001) = 1
PopCount(0b_00000000000000000000000000000101) = 2
PopCount(0b_00000000000000000000000100100011) = 4
PopCount(0b_00000000000000001100101011111110) = 11
PopCount(0b_11111111111111111111111111111110) = 31
BitOperations.PopCountメソッドで立っているビットの数を計上する .NET Core 3.0
Imports System
Imports System.Numerics

Module Sample
  Sub Main()
    ' BitOperations.PopCountメソッドメソッドはUInteger/ULongに対してのみ使用できる
    Dim val As UInteger = &B_0000_0000_0000_0001_1000_0000_0000_0000UI

    ' BitOperations.PopCountで立っているビット(1のビット)の数を求める
    Dim popcnt As Integer = BitOperations.PopCount(val)

    For Each _val As UInteger In New UInteger() {&H1UI, &H5UI, &H123UI, &HCAFEUI, &HFFFFFFFEUI}
      popcnt = BitOperations.PopCount(_val)

      Console.WriteLine($"PopCount({_val.ToBinary()}) = {popcnt}")
    Next
  End Sub

#Region "数値を二進数表記で文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As UInteger) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
PopCount(&B_00000000000000000000000000000001) = 1
PopCount(&B_00000000000000000000000000000101) = 2
PopCount(&B_00000000000000000000000100100011) = 4
PopCount(&B_00000000000000001100101011111110) = 11
PopCount(&B_11111111111111111111111111111110) = 31

2進対数・lb n (Log2)

Log2メソッドは、2を底とした対数(2進対数、⌊log2n⌋・⌊lb n⌋)を求めます。

Math.Logメソッドによっても2進対数を求めることはできますが、LeadingZeroCountメソッド相当のビット演算によって計算される点、これに従い戻り値が整数(⌊lb n⌋)となる点が異なります。 たとえば、値が100(2)から111(2)の場合、Log2メソッドの結果はすべて2(10)となります。 Mathクラスを使った場合にMath.Floor(Math.Log(2.0, n))とすることで得られる値が、Log2メソッドの結果となります。

Log2メソッドは、uint/UInteger, ulong/ULongの整数型のみに対して定義されています。 結果はint/Integerで返されます。

BitOperations.Log2メソッドで2進対数を求める .NET Core 3.0
using System;
using System.Numerics;

static class Sample {
  static void Main()
  {
    // BitOperations.Log2メソッドはuint/ulongに対してのみ使用できる
    uint val = 0b_1000_0000_0000_0000_0000_0000_0000_0001;

    // BitOperations.Log2で2を底とした対数を求める
    int log2 = BitOperations.Log2(val);

    // Math.Logで求める場合との比較
    foreach (var _val in new uint[] {0x1u, 0x5u, 0x123u, 0xCAFEu, 0x80000000u, 0xFFFFFFFEu}) {
      Console.WriteLine($"val = {_val.ToBinary()}\tBitOperations.Log2(val) = {BitOperations.Log2(_val)}\tMath.Log(val, 2) = {Math.Log(_val, 2.0)}");
    }
  }

#region "数値を二進数表記で文字列化するためのメソッド"
  static string ToBinary(this uint number) => "0b_" + Convert.ToString(number, 2).PadLeft(8 * sizeof(uint), '0');
#endregion
}
実行結果
val = 0b_00000000000000000000000000000001	BitOperations.Log2(val) = 0	Math.Log(val, 2) = 0
val = 0b_00000000000000000000000000000101	BitOperations.Log2(val) = 2	Math.Log(val, 2) = 2.321928094887362
val = 0b_00000000000000000000000100100011	BitOperations.Log2(val) = 8	Math.Log(val, 2) = 8.184875342908285
val = 0b_00000000000000001100101011111110	BitOperations.Log2(val) = 15	Math.Log(val, 2) = 15.665280393678295
val = 0b_10000000000000000000000000000000	BitOperations.Log2(val) = 31	Math.Log(val, 2) = 31.000000000000004
val = 0b_11111111111111111111111111111110	BitOperations.Log2(val) = 31	Math.Log(val, 2) = 31.999999999328193
BitOperations.Log2メソッドで2進対数を求める .NET Core 3.0
Imports System
Imports System.Numerics

Module Sample
  Sub Main()
    ' BitOperations.Log2メソッドはuint/ulongに対してのみ使用できる
    Dim val As UInteger = &B_1000_0000_0000_0000_0000_0000_0000_0001UI

    ' BitOperations.Log2で2を底とした対数を求める
    Dim log2 As Integer = BitOperations.Log2(val)

    ' Math.Logで求める場合との比較
    For Each _val As UInteger In New UInteger() {&H1UI, &H5UI, &H123UI, &HCAFEUI, &H80000000UI, &HFFFFFFFEUI}
      Console.WriteLine($"val = {_val.ToBinary()}   BitOperations.Log2(val) = {BitOperations.Log2(_val)}   Math.Log(val, 2) = {Math.Log(_val, 2.0)}")
    Next
  End Sub

#Region "数値を二進数表記で文字列化するためのメソッド"
  <System.Runtime.CompilerServices.Extension> _
  Function ToBinary(ByVal number As UInteger) As String
    Return "&B_" + Convert.ToString(number, 2).PadLeft(8 * Len(number), "0"c)
  End Function
#End Region
End Module
実行結果
val = &B_00000000000000000000000000000001   BitOperations.Log2(val) = 0   Math.Log(val, 2) = 0
val = &B_00000000000000000000000000000101   BitOperations.Log2(val) = 2   Math.Log(val, 2) = 2.321928094887362
val = &B_00000000000000000000000100100011   BitOperations.Log2(val) = 8   Math.Log(val, 2) = 8.184875342908285
val = &B_00000000000000001100101011111110   BitOperations.Log2(val) = 15   Math.Log(val, 2) = 15.665280393678295
val = &B_10000000000000000000000000000000   BitOperations.Log2(val) = 31   Math.Log(val, 2) = 31.000000000000004
val = &B_11111111111111111111111111111110   BitOperations.Log2(val) = 31   Math.Log(val, 2) = 31.999999999328193

数値・文字列間での基数変換

ここでは、ビット演算に関連する事項として、2進・16進の数値・文字列を相互に変換する方法について解説します。

基数を指定した数値から文字列への変換

基数を指定して数値を文字列化するには、Convert.ToStringメソッドを使用します。 引数toBaseに基数を指定すると、その基数で数値を文字列化することができます。 基数には2, 8, 10, 16のいずれかを指定できます。

このメソッドでは0埋め・桁揃えをすることはできないので、そういった目的にはString.PadLeftメソッド等と組み合わせて使用します。 また、基数に16を指定した場合は、09と小文字afが用いられるため、16進数を大文字で表記したい場合はさらにString.ToUpperメソッドを組み合わせる必要があります。

Convert.ToStringとString.PadLeftを使って、基数と桁数を指定して文字列化する
using System;

static class Sample {
  static void Main()
  {
    var n = 123;

    // 基数を指定して値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2)); //  2進数表記で数値nを文字列化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10)); // 10進数表記で数値nを文字列化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16)); // 16進数表記で数値nを文字列化
    Console.WriteLine();

    // 基数と桁数を指定して右揃えで値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2).PadLeft(8)); // 桁数8・右揃えで数値nを 2進数表記化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10).PadLeft(8)); // 桁数8・右揃えで数値nを10進数表記化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16).PadLeft(8)); // 桁数8・右揃えで数値nを16進数表記化
    Console.WriteLine();

    // 基数と桁数を指定して0埋めして値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2).PadLeft(8, '0')); // 桁数8・0埋めして数値nを 2進数表記化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10).PadLeft(8, '0')); // 桁数8・0埋めして数値nを10進数表記化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16).PadLeft(8, '0')); // 桁数8・0埋めして数値nを16進数表記化
    Console.WriteLine();
  }
}
Convert.ToStringとString.PadLeftを使って、基数と桁数を指定して文字列化する
Imports System

Module Sample
  Sub Main()
    Dim n As Integer = 123

    ' 基数を指定して値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2)) '  2進数表記で数値nを文字列化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10)) ' 10進数表記で数値nを文字列化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16)) ' 16進数表記で数値nを文字列化
    Console.WriteLine()

    ' 基数と桁数を指定して右揃えで値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2).PadLeft(8)) ' 桁数8・右揃えで数値nを 2進数表記化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10).PadLeft(8)) ' 桁数8・右揃えで数値nを10進数表記化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16).PadLeft(8)) ' 桁数8・右揃えで数値nを16進数表記化
    Console.WriteLine()

    ' 基数と桁数を指定して0埋めして値を文字列化
    Console.WriteLine("base =  2: {0}", Convert.ToString(n,  2).PadLeft(8, "0"c)) ' 桁数8・0埋めして数値nを 2進数表記化
    Console.WriteLine("base = 10: {0}", Convert.ToString(n, 10).PadLeft(8, "0"c)) ' 桁数8・0埋めして数値nを10進数表記化
    Console.WriteLine("base = 16: {0}", Convert.ToString(n, 16).PadLeft(8, "0"c)) ' 桁数8・0埋めして数値nを16進数表記化
    Console.WriteLine()
  End Sub
End Module
実行結果
base =  2: 1111011
base = 10: 123
base = 16: 7b

base =  2:  1111011
base = 10:      123
base = 16:       7b

base =  2: 01111011
base = 10: 00000123
base = 16: 0000007b


10進数・16進数に限れば、ToStringメソッドやConsole.WriteLineメソッドなどの書式を指定できる文字列化メソッドを使うことでも文字列化することができます。 これらのメソッドで10進形式(D)・16進形式(X)を表す書式指定文字列を指定すれば、その書式に基づいて文字列化されます。 これらに加えて、.NET 8以降であれば2進形式(B)の書式指定文字列も使用できます。

ToStringメソッドを使って0埋め・桁揃えした10進・16進・2進形式で文字列化する .NET 8
using System;

static class Sample {
  static void Main()
  {
    var n = 123;

    // ToStringメソッドに書式を指定して文字列化
    Console.WriteLine("format = D : {0}", n.ToString("D"));  // 10進数表記で数値nを文字列化
    Console.WriteLine("format = X : {0}", n.ToString("X"));  // 16進数表記で数値nを文字列化(A-Fを大文字で表記)
    Console.WriteLine("format = x : {0}", n.ToString("x"));  // 16進数表記で数値nを文字列化(a-fを小文字で表記)
    Console.WriteLine("format = B : {0}", n.ToString("B"));  // 2進数表記で数値nを文字列化(.NET 8以降で使用可能)
    Console.WriteLine("format = D8: {0}", n.ToString("D8")); // 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine("format = X8: {0}", n.ToString("X8")); // 16進数表記で数値nを文字列化(A-Fを大文字で表記・桁数8で0埋め)
    Console.WriteLine("format = x8: {0}", n.ToString("x8")); // 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で0埋め)
    Console.WriteLine("format = B8: {0}", n.ToString("B8")); // 2進数表記で数値nを文字列化(桁数8で0埋め・.NET 8以降で使用可能)
  }
}
ToStringメソッドを使って0埋め・桁揃えした10進・16進・2進形式で文字列化する .NET 8
Imports System

Module Sample
  Sub Main()
    Dim n As Integer = 123

    ' ToStringメソッドに書式を指定して文字列化
    Console.WriteLine("format = D : {0}", n.ToString("D"))  ' 10進数表記で数値nを文字列化
    Console.WriteLine("format = X : {0}", n.ToString("X"))  ' 16進数表記で数値nを文字列化(A-Fを大文字で表記)
    Console.WriteLine("format = x : {0}", n.ToString("x"))  ' 16進数表記で数値nを文字列化(a-fを小文字で表記)
    Console.WriteLine("format = D8: {0}", n.ToString("D8")) ' 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine("format = B : {0}", n.ToString("B"))  ' 2進数表記で数値nを文字列化(.NET 8以降で使用可能)
    Console.WriteLine("format = X8: {0}", n.ToString("X8")) ' 16進数表記で数値nを文字列化(A-Fを大文字で表記・桁数8で0埋め)
    Console.WriteLine("format = x8: {0}", n.ToString("x8")) ' 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で0埋め)
    Console.WriteLine("format = B8: {0}", n.ToString("B8")) ' 2進数表記で数値nを文字列化(桁数8で0埋め・.NET 8以降で使用可能)
  End Sub
End Module
実行結果
format = D : 123
format = X : 7B
format = x : 7b
format = D8: 00000123
format = B : 1111011
format = X8: 0000007B
format = x8: 0000007b
format = B8: 01111011

また、複合書式指定を使用することで、0埋め・桁揃えも同時に行うことができます。 複合書式指定は、ConsoleクラスStreamWriterクラスStringBuilderクラスのWriteLine等のメソッドでサポートされます。 (書式指定子 §.書式化に対応したメソッドと書式指定子)

複合書式指定を使用し、0埋め・桁揃えした10進・16進形式で文字列化する
using System;

static class Sample {
  static void Main()
  {
    var n = 123;

    // Console.WriteLineメソッドで複合書式指定によって文字列化・表示する
    Console.WriteLine("alignment = -, format = D : '{0:D}'", n);   // 10進数表記で数値nを文字列化
    Console.WriteLine("alignment = 8, format = D : '{0,8:D}'", n); // 10進数表記で数値nを文字列化(桁数8で右揃え)
    Console.WriteLine("alignment = -, format = D8: '{0:D8}'", n);  // 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine("alignment = 8, format = x : '{0,8:x}'", n); // 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で右揃え)
    Console.WriteLine("alignment = -, format = X8: '{0:X8}'", n);  // 16進数表記で数値nを文字列化(A-Zを大文字で表記・桁数8で0埋め)
  }
}
複合書式指定を使用し、0埋め・桁揃えした10進・16進形式で文字列化する
Imports System

Module Sample
  Sub Main()
    Dim n As Integer = 123

    ' Console.WriteLineメソッドで複合書式指定によって文字列化・表示する
    Console.WriteLine("alignment = -, format = D : '{0:D}'", n)   ' 10進数表記で数値nを文字列化
    Console.WriteLine("alignment = 8, format = D : '{0,8:D}'", n) ' 10進数表記で数値nを文字列化(桁数8で右揃え)
    Console.WriteLine("alignment = -, format = D8: '{0:D8}'", n)  ' 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine("alignment = 8, format = x : '{0,8:x}'", n) ' 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で右揃え)
    Console.WriteLine("alignment = -, format = X8: '{0:X8}'", n)  ' 16進数表記で数値nを文字列化(A-Zを大文字で表記・桁数8で0埋め)
  End Sub
End Module
実行結果
alignment = -, format = D : '123'
alignment = 8, format = D : '     123'
alignment = -, format = D8: '00000123'
alignment = 8, format = x : '      7b'
alignment = -, format = X8: '0000007B'

複合書式指定において、alignmentに正の値を指定すると右揃え、負の値を指定すると左揃えとなります。

複合書式指定は、文字列補間($"..."形式の文字列リテラル内)でも使用することができます。 文字列補間は、C# 6.0/VB 14以降で使用できます。

文字列補間で複合書式指定を使用し、0埋め・桁揃えした10進・16進形式で文字列化する 
using System;

static class Sample {
  static void Main()
  {
    var n = 123;

    // 文字列補間と複合書式指定を使って文字列化・表示する
    Console.WriteLine($"alignment = -, format = D : '{n:D}'");   // 10進数表記で数値nを文字列化
    Console.WriteLine($"alignment = 8, format = D : '{n,8:D}'"); // 10進数表記で数値nを文字列化(桁数8で右揃え)
    Console.WriteLine($"alignment = -, format = D8: '{n:D8}'");  // 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine($"alignment = 8, format = x : '{n,8:x}'"); // 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で右揃え)
    Console.WriteLine($"alignment = -, format = X8: '{n:X8}'");  // 16進数表記で数値nを文字列化(A-Zを大文字で表記・桁数8で0埋め)
  }
}
文字列補間で複合書式指定を使用し、0埋め・桁揃えした10進・16進形式で文字列化する 
Imports System

Module Sample
  Sub Main()
    Dim n As Integer = 123

    ' 文字列補間と複合書式指定を使って文字列化・表示する
    Console.WriteLine($"alignment = -, format = D : '{n:D}'")   ' 10進数表記で数値nを文字列化
    Console.WriteLine($"alignment = 8, format = D : '{n,8:D}'") ' 10進数表記で数値nを文字列化(桁数8で右揃え)
    Console.WriteLine($"alignment = -, format = D8: '{n:D8}'")  ' 10進数表記で数値nを文字列化(桁数8で0埋め)
    Console.WriteLine($"alignment = 8, format = x : '{n,8:x}'") ' 16進数表記で数値nを文字列化(a-fを小文字で表記・桁数8で右揃え)
    Console.WriteLine($"alignment = -, format = X8: '{n:X8}'")  ' 16進数表記で数値nを文字列化(A-Zを大文字で表記・桁数8で0埋め)
    Console.WriteLine()
  End Sub
End Module
実行結果
alignment = -, format = D : '123'
alignment = 8, format = D : '     123'
alignment = -, format = D8: '00000123'
alignment = 8, format = x : '      7b'
alignment = -, format = X8: '0000007B'

基数を指定した文字列から数値への変換

基数を指定して文字列を数値化するには、Convert.ToInt32等のメソッドを使用することができます。 引数fromBaseに基数を指定すると、その基数で表記されている数値として文字列を数値化することができます。 基数には2, 8, 10, 16のいずれかを指定できます。

基数が10の場合において、例えば文字列2147483648をToInt32メソッドで変換する場合は、値が型(Int32)の扱える範囲を超えるため、例外OverflowExceptionがスローされます。 一方、基数が10以外の場合、文字列はその型におけるメモリ上での表現であるものとして変換されます。 そのため、例えば文字列80000000を基数16としてToInt32メソッドで数値に変換する場合は、オーバーフローとはならず、値-2147483648として変換されます。 ただしこの場合でも、値が型の扱える範囲を超えるような場合はOverflowExceptionがスローされます。

基数が10の場合に限り、符号+および-が前置された文字列の場合でも例外はスローされません。 それ以外の基数で符号が前置されている場合は、FormatExceptionとなります。 0埋めされた文字列(数値に桁揃えの0が先行する)場合でも、そのまま変換できます。 一方、前後に空白等が含まれる場合はFormatExceptionとなります。

このほか、0x&Hなどのプレフィックスや、ULなどのサフィックスが含まれる文字列を数値化することはできません。 この場合FormatExceptionがスローされます。 また、桁区切り記号_を含む文字列の場合も同様です。 プレフィックス・サフィックス・桁区切り文字が含まれる文字列を数値化したい場合は、事前に取り除いておく必要があります。

16進表記の場合はafおよびAFは大文字小文字が混在していても数値化することができます。

Convert.ToInt32メソッドを使って基数を指定して文字列を数値化する
using System;

static class Sample {
  static void Main()
  {
    string s = "100";
    Console.WriteLine($"s = \"{s}\"");

    Console.WriteLine("base =  2 : {0}", Convert.ToInt32(s,  2)); // 文字列を 2進数形式の数値としてintに変換する
    Console.WriteLine("base = 10 : {0}", Convert.ToInt32(s, 10)); // 文字列を10進数形式の数値としてintに変換する
    Console.WriteLine("base = 16 : {0}", Convert.ToInt32(s, 16)); // 文字列を16進数形式の数値としてintに変換する
    Console.WriteLine();

    // 基数16で変換する場合は、大文字小文字が混在していても問題なく変換される
    s = "cafe"; Console.WriteLine("s = \"{0}\", base = 16 : {1}", s, Convert.ToInt32(s, 16));
    s = "CaFe"; Console.WriteLine("s = \"{0}\", base = 16 : {1}", s, Convert.ToInt32(s, 16));

    // 基数10以外で変換する場合は、変換先の型におけるメモリ上での表現として解釈される
    // (解釈の結果、型の扱える範囲を超える場合はOverflowExceptionとなる)
    s = "80000000"; Console.WriteLine("s = \"{0}\", base = 16 : {1}", s, Convert.ToInt32(s, 16));

    // 基数10で変換する場合は、符号が前置されていても問題なく変換される
    // (基数10以外では、FormatExceptionとなる)
    s = "+100"; Console.WriteLine("s = \"{0}\", base = 10 : {1}", s, Convert.ToInt32(s, 10));
    s = "-100"; Console.WriteLine("s = \"{0}\", base = 10 : {1}", s, Convert.ToInt32(s, 10));

    // 0埋めされている場合でも、問題なく変換される
    s = "010"; Console.WriteLine("s = \"{0}\", base = 16 : {1}", s, Convert.ToInt32(s, 16));
    s = "010"; Console.WriteLine("s = \"{0}\", base = 10 : {1}", s, Convert.ToInt32(s, 10));

    // 前後に空白がある場合はFormatExceptionとなるので、Trim()メソッドであらかじめ除去しておく必要がある
    s = " 1 "; Console.WriteLine("s = \"{0}\", base = 16 : {1}", s, Convert.ToInt32(s.Trim(), 16));
    s = " 1 "; Console.WriteLine("s = \"{0}\", base = 10 : {1}", s, Convert.ToInt32(s.Trim(), 10));
  }
}
Convert.ToInt32メソッドを使って基数を指定して文字列を数値化する
Imports System

Module Sample
  Sub Main()
    Dim s As String = "100"
    Console.WriteLine($"s = ""{s}""")

    Console.WriteLine("base =  2 : {0}", Convert.ToInt32(s,  2)) ' 文字列を 2進数形式の数値としてIntegerに変換する
    Console.WriteLine("base = 10 : {0}", Convert.ToInt32(s, 10)) ' 文字列を10進数形式の数値としてIntegerに変換する
    Console.WriteLine("base = 16 : {0}", Convert.ToInt32(s, 16)) ' 文字列を16進数形式の数値としてIntegerに変換する
    Console.WriteLine()

    ' 基数16で変換する場合は、大文字小文字が混在していても問題なく変換される
    s = "cafe" : Console.WriteLine("s = ""{0}"", base = 16 : {1}", s, Convert.ToInt32(s, 16))
    s = "CaFe" : Console.WriteLine("s = ""{0}"", base = 16 : {1}", s, Convert.ToInt32(s, 16))

    ' 基数10以外で変換する場合は、変換先の型におけるメモリ上での表現として解釈される
    ' (解釈の結果、型の扱える範囲を超える場合はOverflowExceptionとなる)
    s = "80000000" : Console.WriteLine("s = ""{0}"", base = 16 : {1}", s, Convert.ToInt32(s, 16))

    ' 基数10で変換する場合は、符号が前置されていても問題なく変換される
    ' (基数10以外では、FormatExceptionとなる)
    s = "+100" : Console.WriteLine("s = ""{0}"", base = 10 : {1}", s, Convert.ToInt32(s, 10))
    s = "-100" : Console.WriteLine("s = ""{0}"", base = 10 : {1}", s, Convert.ToInt32(s, 10))

    ' 0埋めされている場合でも、問題なく変換される
    s = "010" : Console.WriteLine("s = ""{0}"", base = 16 : {1}", s, Convert.ToInt32(s, 16))
    s = "010" : Console.WriteLine("s = ""{0}"", base = 10 : {1}", s, Convert.ToInt32(s, 10))

    ' 前後に空白がある場合はFormatExceptionとなるので、Trim()メソッドであらかじめ除去しておく必要がある
    s = " 1 " : Console.WriteLine("s = ""{0}"", base = 16 : {1}", s, Convert.ToInt32(s.Trim(), 16))
    s = " 1 " : Console.WriteLine("s = ""{0}"", base = 10 : {1}", s, Convert.ToInt32(s.Trim(), 10))
  End Sub
End Module
実行結果
s = "100"
base =  2 : 4
base = 10 : 100
base = 16 : 256

s = "cafe", base = 16 : 51966
s = "CaFe", base = 16 : 51966
s = "80000000", base = 16 : -2147483648
s = "+100", base = 10 : 100
s = "-100", base = 10 : -100
s = "010", base = 16 : 16
s = "010", base = 10 : 10
s = " 1 ", base = 16 : 1
s = " 1 ", base = 10 : 1

Convert.ToInt32メソッドは文字列をint/Integerに変換します。 このほかにも、変換先・値の型に合わせて以下のメソッドを使用することができます。

基数を指定して文字列→数値の変換を行うメソッド
メソッド 変換先の型
C# VB
Convert.ToSByte sbyte SByte
Convert.ToByte byte Byte
Convert.ToInt16 short Short
Convert.ToUInt16 ushort UShort
Convert.ToInt32 int Integer
Convert.ToUInt32 uint UInteger
Convert.ToInt64 long Long
Convert.ToUInt64 ulong ULong

このほか、10進数に限れば、int.Parse/Integer.Parseメソッド(Int32.Parse)や、int.TryParse/Integer.TryParseメソッド(Int32.TryParse)を使うことで文字列から数値への変換ができます。 詳しくは基本型の型変換 §.文字列からの変換 (Parse, TryParse)を参照してください。

関連事項

任意長のビット列に対する演算

ビット演算子・BitOperationsクラスでは、固定長の整数型に対する演算のみが定義されています。 任意長のビット列に対してビット演算を扱いたい場合は、使用できる演算はNOT・AND等の基礎的な論理演算等に限られるものの、BitArrayクラスBigInteger構造体を使用することができます。 詳しくは以下のページを参照してください。

集合演算

集合同士の和・積・差・対称差などの演算や包含関係の演算などを行いたい場合は、HashSet・SortedSetを使うことができます。 詳しくは以下のページを参照してください。