次の方法で共有


符号なし右シフト演算子

メモ

この記事は機能仕様についてです。 仕様は、機能の設計ドキュメントとして使用できます。 これには、提案された仕様の変更および機能の設計と開発時に必要な情報が含まれます。 これらの記事は、提案された仕様の変更が決定され、現在の ECMA 仕様に組み込まれるまで公開されます。

機能の仕様と行われた実装では、いくつかの違いがあることがあります。 これらの違いは、関連する言語設計ミーティング (LDM) メモに取り上げられています。

機能仕様を C# 言語標準に導入するプロセスの詳細については、仕様に関する記事を参照してください。

チャンピオンの課題: https://github.com/dotnet/csharplang/issues/4682

まとめ

符号なし右シフト演算子は、組み込み演算子 (プリミティブ整数型の場合) およびユーザー定義演算子として C# によってサポートされることになります。

目的

符号付き整数値を使用する場合、各シフトで上位ビットをレプリケートせずにビットを右にシフトする必要があるのも珍しくありません。 これは、通常のシフト演算子を使用するプリミティブ整数型では実現できますが、シフト操作の前に符号なし型にキャストし、必要になった後にキャストバックします。 ライブラリが公開を計画している汎用数学インターフェイスのコンテキスト内では、この型には、必ずしも署名されていない対応するものが汎用数学コードによって事前に定義済みまたは既知であるとは限らないにもかかわらず、アルゴリズムは符号なし右シフト演算を実行する機能に依存する場合があるため、より問題が深刻になる可能性があります。

詳細な設計

演算子と区切り記号

セクション §6.4.6 は、>>> 演算子 (符号なし右シフト演算子) を含むように調整されます。

unsigned_right_shift
    : '>>>'
    ;

unsigned_right_shift_assignment
    : '>>>='
    ;

nsigned_right_shiftunsigned_right_shift_assignment の生成では、トークンの間にどのような種類の文字も (空白も含め) 許可されません。 これらのプロダクションは、type_parameter_listの正しい処理が可能になるように特別に扱われます。

シフト演算子

セクション §12.11 は、>>> 演算子 (符号なし右シフト演算子) を含むように調整されます。

ビットシフト演算の実行には、<<>>、および >>> 演算子が使用されます。

shift_expression
    : additive_expression
    | shift_expression '<<' additive_expression
    | shift_expression right_shift additive_expression
    | shift_expression unsigned_right_shift additive_expression
    ;

フォーム x << count または x >> count または x >>> countの操作では、2 項演算子のオーバーロード解決 (§12.4.5) が適用され、特定の演算子の実装が選択されます。 オペランドは選択した演算子のパラメーター型に変換され、結果の型は演算子の戻り値の型になります。

定義済みの符号なしシフト演算子では、最新の実装で現在サポートされている定義済みの符号付きシフト演算子と同じシグネチャ セットをサポートします。

  • 右シフト:

    int operator >>>(int x, int count);
    uint operator >>>(uint x, int count);
    long operator >>>(long x, int count);
    ulong operator >>>(ulong x, int count);
    nint operator >>>(nint x, int count);
    nuint operator >>>(nuint x, int count);
    

    >>> 演算子は、以下に説明する方法で計算されたビット数だけ x を右にシフトします。

    x の下位ビットは破棄され、残りのビットは右にシフトされ、上位の空のビット位置は 0 に設定されます。

定義済みの演算子の場合、シフトするビット数は次のように計算されます。

  • x の型が int または uintの場合、シフト カウントは count の下位 5 ビットによって与えられます。 つまり、シフト カウントは count & 0x1F から計算されます。
  • x の型が long または ulongの場合、シフト カウントは count の下位 6 ビットによって与えられます。 つまり、シフト カウントは count & 0x3F から計算されます。

結果のシフト カウントが 0 の場合、シフト演算子は単に x の値を返します。

シフト演算が原因でオーバーフローが発生することはなく、checkedunchecked のコンテキストで同じ結果が生成されることはありません。

代入演算子

セクション §12.21 は、次のように unsigned_right_shift_assignment を含むように調整されます。

assignment_operator
    : '='
    | '+='
    | '-='
    | '*='
    | '/='
    | '%='
    | '&='
    | '|='
    | '^='
    | '<<='
    | right_shift_assignment
    | unsigned_right_shift_assignment
    ;

整数型

整数型 §8.3.6 セクションは、>>> 演算子に関する情報を含むように調整されます。 関連する箇条書きは次のとおりです。

  • 二項 <<>>、および >>> 演算子の場合、左オペランドは T 型に変換されます。ここで、T はオペランドのすべての使用可能な値を完全に表すことができる intuintlong、および ulong の最初です。 その後、T型の精度を使用して操作が実行され、結果の型は Tになります。

定数の表現

演算子 >>> は、定数式で許可されているコンストラクトの集合 に追加され、§12.23で新たに定義されます。

演算子のオーバーロード

演算子 >>> は、§12.4.3 でオーバーロード可能な二項演算子のセットに追加されます。

リフト演算子

演算子 >>> は、§12.4.8 でリフトフォームを許可する二項演算子のセットに追加されます。

演算子の優先順位と結合規則

セクション §12.4.2 は、>>> 演算子を "Shift" カテゴリに追加し、>>>= 演算子を "Assignment and lambda expression" カテゴリに追加するように調整されます。

文法のあいまいさ

>>> 演算子は、通常の >> 演算子として §6.2.5 で説明されているのと同じ文法のあいまいさの対象となります。

Operators

§15.10 セクションは、>>> 演算子を含むように調整されます。

overloadable_binary_operator
    : '+'   | '-'   | '*'   | '/'   | '%'   | '&'   | '|'   | '^'   | '<<'
    | right_shift | unsigned_right_shift | '=='  | '!='  | '>'   | '<'   | '>='  | '<='
    ;

バイナリ演算子

>>> 演算子のシグネチャは、>> 演算子のシグネチャの §15.10.3 あるものと同じルールに従います。

メタデータ名

ECMA-335 のセクション "I.10.3.2 二項演算子" は、符号なし右シフト演算子 (op_UnsignedRightShift) 用に名前を既に予約しています。

Linq 式ツリー

>>> 演算子は Linq 式ツリーではサポートされません。符号付き型に対する定義済みの >>> 演算子のセマンティクスは、符号なし型と戻り値に変換を追加しないと正確に表すことができないためです。 詳細については、「https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator」を参照してください。

動的バインディング

動的バインディングでは、System.Linq.Expressions.ExpressionType 列挙型の値を使用して、バイナリ演算子の種類をランタイム バインダーに通信しているように見えます。 符号なし右シフト演算子を具体的に表すメンバーがないため、>>> 演算子の動的バインディングはサポートされず、静的および動的バインディング (§12.3) セクションが調整されてそれが反映されます。

デメリット

代替

Linq 式ツリー

>>> 演算子は Linq 式ツリーでサポートされます。

  • ユーザー定義演算子の場合、演算子メソッドを指す BinaryExpression ノードが作成されます。
  • 定義済みの演算子の場合
    • 最初のオペランドが署名された型の場合は、BinaryExpression ノードが作成されます。
    • 最初のオペランドが符号付き型の場合、最初のオペランドから符号なし型への変換が追加され、BinaryExpression ノードが作成され、結果の符号付き型への変換が追加されます。

次に例を示します。

Expression<System.Func<int, int, int>> z = (x, y) => x >>> y; // (x, y) => Convert((Convert(x, UInt32) >> y), Int32)

Resolution:

却下、詳細については、「https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md#unsigned-right-shift-operator」を参照してください。

未解決の質問

デザイン ミーティング

https://github.com/dotnet/csharplang/blob/main/meetings/2022/LDM-2022-02-09.md