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
となります。 複合代入演算子を使う場合は、自動的に代入先の型にキャストされます。
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
を除く各整数型に対して使用できます。 演算の結果は、左右のオペランド(項)が同じ型の場合はその型、異なる型の場合はより大きい型の方に拡大変換されます。
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
上記の演算子をbool
・Boolean
に対して使用すると、ビットごとの演算ではなく単一のブール値に対する演算を行う論理演算子となります。 ただしVBでは、ブール値に対して論理積・論理和を求める場合は通常AndAlso
・OrElse
演算子を使います 詳細は論理演算子 §.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)を超える数を指定できるほか、負数を指定することもできます。 シフト量が負の場合は、逆方向への回転シフトになります。
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
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
で返されます。
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
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
で返されます。
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
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
で返されます。
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
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を指定した場合は、0
〜9
と小文字a
〜f
が用いられるため、16進数を大文字で表記したい場合はさらにString.ToUpperメソッドを組み合わせる必要があります。
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();
}
}
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
)の書式指定文字列も使用できます。
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以降で使用可能)
}
}
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等のメソッドでサポートされます。 (書式指定子 §.書式化に対応したメソッドと書式指定子)
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埋め)
}
}
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以降で使用できます。
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埋め)
}
}
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進表記の場合はa
〜f
およびA
〜F
は大文字小文字が混在していても数値化することができます。
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));
}
}
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を使うことができます。 詳しくは以下のページを参照してください。