SHIFT

ビット演算を行う前の基礎知識

こちらを参照。→OR,AND,XOR



SHIFT

lua.txtの記述

SHIFT(a,shift)
算術シフトをします。shiftが正の数だと左シフト、負の数だと右シフトになります。
a ビット演算を行いたい数値
shift ビットシフトを行う方向

解説

渡された数値を左、または右に指定された数だけビットシフトします。

左シフトの場合

2つ目の引数であるshiftの値が正の数(つまりゼロ以上、shift>0)だと、
左側にビットシフトを行います。


戻り値

演算結果を返します。
次のように記述すると、
resultには40が代入されます。
result = SHIFT( 5,3 )

計算方法

先ほどのSHIFT( 5,3 )を例にして計算してみましょう。

値\ビット 8 7 6 5 4 3 2 1
5 0 0 0 0 0 1 0 1
結果

次に、各ビットをシフトする方向に移動させます。
この場合、左に3つ移動させることになります。
移動させた後の右3つには0を入れます。
あふれたビットは捨てられます。
注意点として、算術シフトと呼ばれるこの関数は、
一番頭のビット(この場合は8ビット目)はそのままにします。

値\ビット 8 7 6 5 4 3 2 1
5 0 0 0 0 0 1 0 1
結果 0 0 1 0 1 0 0 0

電卓で101000を10進数に変換して40になることを確認しましょう。


右シフトの場合

2つ目の引数であるshiftの値が負の数(つまりゼロ以下、shift<0)だと、
右側にビットシフトを行います。


戻り値

演算結果を返します。
次のように記述すると、
resultには22が代入されます。
result = SHIFT( 91,-2 )

計算方法

先ほどのSHIFT( 91,-2 )を例にして計算してみましょう。

値\ビット 8 7 6 5 4 3 2 1
91 0 1 0 1 1 0 1 1
結果

次に、各ビットをシフトする方向に移動させます。
この場合、右に2つ移動させることになります。
移動させた後の左2つには0を入れます。
あふれたビットは捨てられます。
左シフト同様に一番頭のビットはそのままにします。

値\ビット 8 7 6 5 4 3 2 1
91 0 1 0 1 1 0 1 1
結果 0 0 0 1 0 1 1 0

電卓で10110を10進数に変換して22になることを確認しましょう。



使い道

結果の法則性

まず結果を比較してみましょう。

SHIFT( 5,1 ) 10
SHIFT( 5,2 ) 20
SHIFT( 5,3 ) 40
SHIFT( 5,4 ) 80
SHIFT( 5,5 ) 160

どれも5で割り切れるような気がします。

SHIFT( 5,1 ) 10 2倍
SHIFT( 5,2 ) 20 4倍
SHIFT( 5,3 ) 40 8倍
SHIFT( 5,4 ) 80 16倍
SHIFT( 5,5 ) 160 32倍

2,4,8,16,32...
と続く数字。
これには法則性があり、2のべき乗となっています。

つまり、左シフトでは演算の対象に、2nの数をかけた値が返ってきます。
同様に、右シフトでは2nの数を割った値が返ってきます。
ただし、右シフトの場合値が切り捨てられます。


なぜビットシフトを行うのか?

現在のコンピュータの性能ではそれほど差が感じられませんが、
乗除よりもビット演算のほうが高速に計算でき、
昔はよく使われていたようです。

ループ内で何度も行われる乗除で使うと、速度が向上する…かもしれないです。。。



注意点


一番上位のビットを移動しない理由

一番上位のビットは符号ビットと呼ばれ、(ただしunsigned系は含まない)
プラスの値かマイナスの値かを保存しています。
そのため、シフト演算を行い符号ビットを書き換えてしまっては正しい値が得られません。

純粋にすべてのビットをシフトする演算方法は論理シフトと呼ばれています。


小数点の扱い

演算対象の値が小数点の場合、整数値に丸めて処理が行われます。
このとき、+0.5までが切り捨ての対象となり、以降は切り上げとなります。
0.5が含まれるので注意してください。

  引数として渡される数
2.50 2
2.51 3

四捨五入ではありません。


値のオーバーフロー

試しに、下のようなスクリプトを実行します。
SHIFT( 1,31 )

正しく計算ができれば、2147483648となっているはずです。
ですが、特定の環境では-2147483648と表示されることがあります。
これはなぜでしょう?

値の上限

変数には値の上限というものがあります。
数字の大きさは無限であり、これを完全に記憶するのは不可能です。
またメモリの制限もあり、上限を作らざるを得ないようになります。

Luaは型という概念を余り意識しなくてもいい言語ですが、
上限を見る限り、内部ではint型を使っているようにみえます。

int型は大体の環境では32ビットとされています。
なぜ大体かというと、処理系によって単位がまちまちだからです。
32ビットOSとかCPUとかの問題です。
ここからはint = 32ビットとして話を進めていきます。

int型の値の範囲は-2,147,483,648~2,147,483,647とされていて、
丁度先ほどの間違った答えである-2147483648と一致します。

このように、値が大きくなりすぎて上限を超えると、
値が逆に小さくなってしまう現象のことをオーバーフローと呼びます。

メモリのチェックが甘かった昔のゲーム機などでもよく見られた現象ですね。
マリオ2の残機がゼロに戻ってしまったり、DQ4のカジノで4Gで838861枚購入できたり。

注意点の注意点

編集者の推測も含まれているため、
間違っている場合は訂正をよろしくお願いします。




  • 最終更新:2011-12-14 21:35:02

このWIKIを編集するにはパスワード入力が必要です

認証パスワード