ビット演算

2進数表現

数値や文字といった情報は、コンピュータの中では 2 進数で表されています。2 進数の一つの桁、0 あるいは 1 を表す一つの桁をビットと呼びます。以降のビットを直接操作する関数では、引数に整数をとります。AutoLISP の整数は 32 ビットです。

ここでは直接ビットを操作します。イメージしにくいので、整数の値を 2 進数で表す文字列に変換する関数を定義してみます。

(defun itob (a / i blist mask)
    (setq blist ""
          mask 1
          i 1
    )
    (repeat 32
          (if (and (/= i 1) (= (rem i 8) 1))
              (setq blist (strcat ":" blist))
          )
          (if (zerop (logand a mask))
              (setq blist (strcat "0" blist))
              (setq blist (strcat "1" blist))
          )
          (setq mask (lsh mask 1)
                i (1+ i)
          )
    )
    blist
)

この関数を用いると、整数が内部で 32 ケタの 2 進数でどのように表現されているかが分かります。

_$ (itob 0)⏎
"00000000:00000000:00000000:00000000"
_$ (itob 1) ⏎
"00000000:00000000:00000000:00000001"
_$ (itob -1) ⏎
"11111111:11111111:11111111:11111111"
_$ (itob 65536) ⏎
"00000000:00000001:00000000:00000000"
_$ (itob -65536) ⏎
"11111111:11111111:00000000:00000000"

以降ではこの関数を使って、ビットがどのように変化するか示します。

ビット演算

AutoLISP関数
(~ integer)
integer:整数
引数のビット方式の NOT (1 の補数)を返します。
戻り値:整数

~ 関数は、ビットが 0 のところは 1 に、1のところは 0 に、値を反転させます。

_$ (itob 1) ⏎
"00000000:00000000:00000000:00000001"
_$ (itob (~ 1)) ⏎
"11111111:11111111:11111111:11111110" ; -2

引数が整数以外はエラーになります。

AutoLISP関数
(logand [integer integer...])
integer:整数
複数の整数のビット方式の AND (論理積)の結果を返します。
戻り値:整数

logand 関数は、すべての整数で同じ桁が 1 である場合だけ 1 となり、そのほかは 0 となります。

_$ (itob 240) ⏎
"00000000:00000000:00000000:11110000"
_$ (itob 170) ⏎
"00000000:00000000:00000000:10101010"
_$ (itob (logand 240 170)) ⏎
"00000000:00000000:00000000:10100000" ; 160

引数が整数以外はエラーになります。

AutoLISP関数
(logior [integer integer...])
integer:整数
整数のリストのビット方式の OR (論理和)の結果を返します。
戻り値:整数

logior 関数は、同じ桁が整数の中のでいずれかが 1 である場合は 1 となり、すべての整数で 0 の場合だけ 0 となります。

_$ (itob 240) ⏎
"00000000:00000000:00000000:11110000"
_$ (itob 170) ⏎
"00000000:00000000:00000000:10101010"
_$ (itob (logior 240 170)) ⏎
"00000000:00000000:00000000:11111010" ; 250

1,2,4,8,16…といった2 の乗数同士では加算の意味になります。

_$ (itob (logior 32 4)) ⏎
"00000000:00000000:00000000:00100100"
_$ (itob (+ 32 4)) ⏎
"00000000:00000000:00000000:00100100"

引数が整数以外はエラーになります。

AutoLISP関数
(Boole operator int1 [int2 ...])
operator:整数
int1,int2:整数
ビット方式の汎用ブール演算関数です。
戻り値:整数

Boole 関数は、ビット方式の汎用ブール演算関数です。

引数 operator に演算の種類を指定します。16 種類も用意されていますが、代表的なもの以外はなかなか使わないと思うので、簡単に表にしておきます。

operator 引数 説明
0 NULL 常に0
1 AND (AND A B)
2 AND-2 (AND A (NOT B))
3 Only A A
4 AND-1 (AND (NOT A) B)
5 Only B B
6 XOR (OR (AND A (NOT B))(AND (NOT A) B))
7 OR (OR A B)
8 NOR (NOT (OR A B))
9 XNOR (OR (AND A B) (AND (NOT A)(NOT B)))
10 NOT B (NOT B)
11 ORC2 (OR A (NOT B))
12 NOT A (NOT A)
13 ORC1 (OR (NOT A) B)
14 NAND (NOT (AND A B))
15 SET 常に1

下の例は、logand 関数と同じことをした例です。

_$ (itob 240) ⏎
"00000000:00000000:00000000:11110000"
_$ (itob 170) ⏎
"00000000:00000000:00000000:10101010"
_$ (itob (boole 1 240 170)) ⏎ ;(logand 240 170)と同義
"00000000:00000000:00000000:10100000"
AutoLISP関数
(lsh integer numbits)
integer:整数
numbits:整数
指定されたビット数だけ整数を論理的にビットシフトした結果を返します。
戻り値:整数

lsh 関数は、ビットの桁をシフトします。numbits の値が正の場合は左へ移動し、これは一桁移動するごとに整数に 2 を掛ける操作と同じ意味になります。負の場合は右に移動し、一桁移動するごとに整数を 2 で割る操作と同じ意味になります。移動して空いた端の桁は 0 で埋められます。

_$ (itob 256) ⏎
"00000000:00000000:00000001:00000000"
_$ (itob (lsh 256 2)) ⏎ ;2 回左シフト
"00000000:00000000:00000100:00000000"
_$ (itob (* (* 256 2) 2)) ⏎ ;2 を 2 回かけることは 2 回左シフトと同じ
"00000000:00000000:00000100:00000000"

このようにビット操作が足し算・掛け算の意味と同じになることがありますが、AutoLISP の整数は符号付の整数なので、その点に注意して結果を吟味する必要があります。