

コンピュータプログラミングにおいて、算術シフトはシフト演算子であり、符号付きシフトと呼ばれることもあります(ただし、符号付きオペランドに限定されるわけではありません)。基本的なタイプは、算術左シフトと算術右シフトの2種類です。バイナリ数の場合、オペランドのすべてのビットをシフトするビット単位の操作です。オペランドの各ビットは、指定されたビット数だけ移動され、空いたビット位置が埋められます。論理シフトのようにすべて0で埋められるのではなく、右シフトの場合は、最も左のビット(通常は符号付き整数表現の符号ビット)が複製されてすべての空いた位置が埋められます(これは一種の符号拡張です)。
算術シフトと論理シフトには、それぞれスティッキー右シフトとゼロフィル右シフトという用語を好む著者もいる。[ 7 ]
算術シフトは、符号付き整数を 2 のべき乗で乗算または除算する効率的な方法として役立ちます。符号付きまたは符号なしの 2 進数をnビット左シフトすると、2 nを乗算する効果があります。2の補数符号付き2 進数をnビット右シフトすると、 2 nで除算する効果がありますが、常に切り捨てられます (負の無限大に向かって)。これは、符号付き整数の除算で通常行われる丸め方 (0 に向かって丸める) とは異なります。この不一致により、多くのコンパイラでバグが発生しています。[ 8 ]
例えば、x86命令セットでは、SAR命令(算術右シフト)は符号付き数を2のべき乗で割り、負の無限大に丸めます。[ 9 ]しかし、IDIV命令(符号付き除算)は符号付き数を割り、ゼロに丸めます。したがって、SAR命令を2のべき乗によるIDIV命令に置き換えることはできませんし、その逆もできません。
連邦規格1037Cにおける算術シフトの正式な定義は以下のとおりである。
固定基数表記システムおよび固定小数点表記システムにおける数値表現に適用されるシフトであり、数値の固定小数点部分を表す文字のみが移動されます。算術シフトは通常、丸め処理の影響を除けば、数値を基数の正または負の整数乗で乗算することと同等です。特に浮動小数点表記の場合、論理シフトと算術シフトを比較してください。
FS 1073Cの定義において重要な単語は「通常」です。
しかし、算術右シフトは、特に負の整数の丸め処理において、注意を怠ると大きな落とし穴となります。たとえば、負の整数の通常の2の補数表現では、-1はすべて1で表されます。8ビットの符号付き整数では、これは1111 1111となります。1(または2、3、...、7)だけ算術右シフトすると 、再び1111 1111となり、これは依然として-1です。これは切り捨て(負の無限大方向)に対応しますが、除算の通常の慣例ではありません。
算術右シフトは基数の(正の整数)べき乗による除算(例えば、2進数の場合は2のべき乗による除算)と同等であるとよく言われ、したがって基数のべき乗による除算は算術右シフトとして実装することで最適化できるとされています。(シフターは除算器よりもはるかに単純です。ほとんどのプロセッサでは、シフト命令は除算命令よりも高速に実行されます。)1960年代と1970年代のDEC、IBM、Data General、ANSIなどの企業や機関のプログラミングハンドブック、マニュアル、その他の仕様書には、このような誤った記述が多数あります[ 10 ]。
論理右シフトは、正の数または符号なしの数の場合のみ、基数(通常は2)のべき乗による除算に相当します。算術右シフトは、正の符号付き数の場合、論理右シフトに相当します。Nの補数(通常は2の補数)の負の数に対する算術右シフトは、基数(通常は2)のべき乗による除算にほぼ相当しますが、奇数の場合は切り捨てが適用されます(通常想定される0方向への切り捨てではありません)。
負の数に対する算術右シフトは、符号付き数の1の補数表現において0への丸めを用いた除算と同等であり、これは一部の歴史的なコンピュータで使用されていましたが、現在では一般的には使用されていません。
プログラミング言語CのISO規格(1999年)では、右シフト演算子を2のべき乗による除算で定義しています。[ 11 ]上記の非等価性のため、この規格では負の値を持つ符号付き数の右シフトを明示的に除外しています。このような状況での右シフト演算子の動作は規定されておらず、代わりに各Cコンパイラが負の値を右シフトする際の動作を定義することを要求しています。[注8 ]
C と同様に、C++ もC++20までは符号付き整数の右シフトは実装定義でした。C++20 標準以降、符号付き整数の右シフトは算術シフトとして定義されています。[ 13 ]
一貫した切り捨てが必要なアプリケーションでは、符号付き値に対する算術右シフトが役立ちます。例として、ラスター座標を 2 のべき乗で縮小し、均等な間隔を維持する場合が挙げられます。たとえば、1 だけ右シフトすると、0、1、2、3、4、5、... は 0、0、1、1、2、2、... になり、-1、-2、-3、-4、... は -1、-1、-2、-2、... になり、-2、-2、-1、-1、0、0、1、1、2、2、... と均等な間隔が維持されます。対照的に、ゼロに向かって丸める整数除算では、-1、0、1 はすべて 0 (2 ポイントではなく 3 ポイント) になり、代わりに -2、-1、-1、0、0、0、1、1、2、2、... となり、0 で不規則になります。
>> は、必ずしも算術シフトではありません。通常、左辺に符号付き整数型を使用した場合にのみ算術シフトになります。符号なし整数型を使用した場合は、論理シフトになります。arithmetic-shift、2 番目のオペランドに応じて左シフトと右シフトの両方が可能で、OpenVMS マクロ言語と非常によく似ていますが、R6RS Scheme では両方-rightの-leftバリアントが追加されています。BitsData.BitsshiftshiftLshiftR
この記事は、連邦規格1037C(一般調達局)からのパブリックドメイン資料を組み込んでいます。 2022年1月22日にオリジナルからアーカイブされました。