符号付き vs 符号なし右シフト
>>(符号を保持する算術シフト)と>>>(ゼロで埋める論理シフト)の重要な違いを、負の数について理解します。
Shift Operations
詳細な説明
算術(>>)vs 論理(>>>)右シフト
JavaScriptは両方のシフト演算子を提供し、負の数で区別が重要になります。
算術右シフト(>>)
空いた上位ビットを符号ビット(最左ビット)で埋めます。負の数の符号を保持します:
-16(32ビット) = 11111111111111111111111111110000
-16 >> 1 = 11111111111111111111111111111000 (-8)
-16 >> 2 = 11111111111111111111111111111100 (-4)
数学的な結果はfloor(n / 2^shift)で、負の無限大に向かって丸めます。
論理右シフト(>>>)
符号ビットに関係なく、常に空いた上位ビットを0で埋めます:
-16(32ビット) = 11111111111111111111111111110000
-16 >>> 1 = 01111111111111111111111111111000 (2147483640)
-16 >>> 2 = 00111111111111111111111111111100 (1073741820)
いつ違いが生じるか?
正の数では両演算子は同一の結果:
16 >> 1 = 8
16 >>> 1 = 8
違いは負の数または32ビット値を符号なしとして扱う必要がある場合のみ現れます。
JavaScriptに固有の動作
JavaScriptの数値は64ビット浮動小数点ですが、ビット演算子は32ビット整数で動作します。>>>演算子はJavaScriptで符号付き32ビット整数を符号なしに変換する唯一の方法です:
(-1 >>> 0).toString(16) // "ffffffff" (4294967295)
(-1 >> 0).toString(16) // "-1"
一般的な使用例:符号なしへの変換
function toUint32(n) {
return n >>> 0;
}
TypedArray操作、ハッシュ関数、バイナリプロトコル実装で頻繁に使用されます。
ユースケース
JavaScriptのハッシュ関数実装では、値が符号なし32ビット範囲に収まることを保証するために`>>> 0`を使用します。例えばMurmurHash3やCRC32は符号なし演算を必要とします。`>>> 0`がなければ、JavaScriptの符号付き32ビットビット演算セマンティクスにより中間値が負になり、不正なハッシュ値が生成されます。`(hash * prime) >>> 0`パターンはJavaScriptハッシュライブラリの標準です。