rksoftware

Visual Studio とか C# とかが好きです

C# 11 の新機能を確認「 ジェネリック型数値演算のサポート - 符号なし右シフト演算子 」

C# 11 の新機能を確認しています。目次は次の記事です。
rksoftware.hatenablog.com

今回は 「 ジェネリック型数値演算のサポート - 符号なし右シフト演算子 」。公式 Learn の記事は次です。
learn.microsoft.com

新しい右シフト演算子 >>> ができました。

■ 確認

int i= -1 >>> 1;

ちなみにこのコードは .NET 6 を指定した場合は次のエラーになります。

エラー CS8936 機能 '符号なし右シフト' は C# 10.0 では使用できません。言語バージョン 11.0 以上を使用してください。

■ 実行

実行結果は次のようになります。

int i= -1 >>> 1;
Console.WriteLine(Convert.ToString(i, toBase: 2).PadLeft(32, '0'));
//  01111111111111111111111111111111

■ 右シフト演算

これは結構マニアックな仕様なので、丁寧に基本のシフト演算から確認して行きましょう。

正の数をシフト演算

まずは正の数をシフト演算してみます。11 の位置が左右に移動 (シフト) しているのが分かります。

Console.WriteLine(Convert.ToString(3, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(3 << 1, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(3 >> 1, toBase: 2).PadLeft(32, '0'));
// 00000000000000000000000000000011
// 00000000000000000000000000000110
// 00000000000000000000000000000001

負の数をシフト演算

負の数をシフト演算すると不思議な感じに。左にシフトしたときには、右端に 0 が埋まったのに、右にシフトしたときには左端が 1 で埋まっています。

Console.WriteLine(Convert.ToString(-1, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(-1 << 1, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(-1 >> 1, toBase: 2).PadLeft(32, '0'));
// 11111111111111111111111111111111
// 11111111111111111111111111111110
// 11111111111111111111111111111111

ビットでなく、数値としてみると分かりやすいかもしれません。

Console.WriteLine(4 << 1);
Console.WriteLine(4 >> 1);
Console.WriteLine(-4 << 1);
Console.WriteLine(-4 >> 1);
//  8
//  2
// -8
// -2

■ 普通に 1 の位置がシフトして欲しい

そんな時に今回追加された >>> です。

Console.WriteLine(Convert.ToString(-1, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(-1 << 1, toBase: 2).PadLeft(32, '0'));
Console.WriteLine(Convert.ToString(-1 >>> 1, toBase: 2).PadLeft(32, '0'));
// 11111111111111111111111111111111
// 11111111111111111111111111111110
// 01111111111111111111111111111111

■ これまではこうしていた

これまでは次のように uint にしていたようです。今回の >>> で便利になりましたね!

unchecked
{
    Console.WriteLine(Convert.ToString((uint)-1, toBase: 2).PadLeft(32, '0'));
    Console.WriteLine(Convert.ToString((uint)-1 << 1, toBase: 2).PadLeft(32, '0'));
    Console.WriteLine(Convert.ToString((uint)-1 >> 1, toBase: 2).PadLeft(32, '0'));
}
// 11111111111111111111111111111111
// 11111111111111111111111111111110
// 01111111111111111111111111111111

■ 覚えておきましょう

この機能は使わない人はほとんど使わない機能かもしれません。しかし >>> という演算子は非常に Web 検索が難しいのではないかと思います。出会ったときに検索しなくて済むように覚えておきましょう。