Tcl – ビット演算子

ビット演算子について

ビット演算子は2進数(0と1)で表現した整数の論理演算を行います。演算子の右辺と左辺の数値を2進数で表現した値を使って各桁ごと(ビット毎)に演算します。 ビット演算子の種類は以下の表の種類があります。

ビット演算子の種類
演算子 意味
& ビットごとのAND。
^ ビットごとのXOR(排他的論理和)。
| ビットごとのOR。
~ ビットごとのNOT(1の補数)。ビット補数演算子とも呼ばれている。
a >> b aの各ビットをb桁、右へシフトします。
a << b aの各ビットをb桁、左へシフトします。

ビットごとのAND

ビット演算子のAND(論理積)は右辺と左辺の各桁のビットが共に1の場合のみ1になります。それ以外の組み合わせでは0になります。

右辺 左辺 AND値
0 0 0
0 1 0
1 0 0
1 1 1

[使用例]

% expr 7 & 11
3

[説明]

7と11を2進数(bit)で表現した数値を使ってAND演算します。

 7 : 0111
11 : 1011
----------
     0011 --> 10進数で3を返します。

ビットごとのXOR(排他的論理和)

ビット演算子のXOR(排他的論理和)は右辺と左辺の各桁のビットが、どちらか一方のみが1の場合に1になります。それ以外の組み合わせでは0になります。

右辺 左辺 XOR値
0 0 0
0 1 1
1 0 1
1 1 0

[使用例]

% expr 7 ^ 11
12

[説明]

7と11を2進数(bit)で表現した数値を使ってXOR演算します。

 7 : 0111
11 : 1011
----------
     1100 --> 10進数で 12 を返します。

ビットごとのOR

ビット演算子のOR(論理和)は右辺と左辺の各桁のビットが、どちらか一方、またはどらも1の場合に1になります。それ以外の組み合わせでは0になります。

右辺 左辺 OR値
0 0 0
0 1 1
1 0 1
1 1 1

[使用例]

% expr 6 | 10
14

[説明]

6と10を2進数(bit)で表現した数値を使ってOR演算します。

 6 : 0110
10 : 1010
----------
     1110 --> 10進数で 14 を返します。

ビットごとのNOT(1の補数)

ビット演算子のNOT(否定)は与えられた数値の各ビットを反転します。

ビット NOT値
0 1
1 0

[使用例]

% expr ~ 3
-4

[説明]

3を2進数(bit)で表現した数値を使ってNOT演算します。

 3 : 0011
----------
     1100 --> 10進数で -4 を返します。
メモ

3のビットを反転させたものが12ではなく、なぜ -4 になるのか?

コンピューター内部では、ある値に対する負数を表すのに正数のビットをすべて反転させたものに 1 を加えたもので表現しています。

例えば、4ビットで表現すると、正数値:4(2進数:0100) の負数表記:-4は以下のようになります。

  1. 2進数:0100のビットを反転させると 1011 になります。(1の補数)
  2. 1011 に 1 を加えると 1100 になります。(2の補数)

よって、-4 は2進数の 1100 になります。ちなみに -1 はALL”1″、 0 はALL”0″ になります。

厳密にいうと、最上位ビットが1の時は負数、0であれば正数とするので、4ビットで表した場合、例えば 0001 は-15ではなく 1 になります。

4ビットで数値を表す場合、10進で、符号なし: 0~15 、 符号あり:-8~+7 までの表現になります

      [符号なし]             [符号あり]
 0000 -> 0 1000 ->  8   0000 -> 0 1000 -> -8 
 0001 -> 1 1001 ->  9   0001 -> 1 1001 -> -7 
 0010 -> 2 1010 -> 10   0010 -> 2 1010 -> -6 
 0011 -> 3 1011 -> 11   0011 -> 3 1011 -> -5 
 0100 -> 4 1100 -> 12   0100 -> 4 1100 -> -4 
 0101 -> 5 1101 -> 13   0101 -> 5 1101 -> -3 
 0110 -> 6 1110 -> 14   0110 -> 6 1110 -> -2 
 0111 -> 7 1111 -> 15   0111 -> 7 1111 -> -1 

実際の演算は32ビットや64ビットで演算されているので以下のようになります。

例. 1111 1111 1111 1111 1111 1111 1111 0001 –> -15

右シフト

右シフト演算子は、左辺で指定した数値を右辺で指定した桁数分、右へ移動させます。

[使用例]

% expr 6 >> 1
3

[説明]

数値6の各ビットを1桁、右へシフトします。

 6 : 0110
      ↓ >> 1桁、右へシフトさせる。
     0011 --> 3 を返します。

左シフト

左シフト演算子は、左辺で指定した数値を右辺で指定した桁数分、左へ移動させます。

[使用例]

% expr 6 << 1   ---(1)
12
% expr 6 << 2   ---(2)
24

[説明]

(1)数値6の各ビットを1桁、左へシフトします。

 6 : 0110
      ↓ << 1桁、左へシフトさせる。
     1100 --> 12 を返します。

(2) 数値6の各ビットを2桁、左へシフトします。

 6 : 0000 0110
         ↓ << 2桁、左へシフトさせる。
     0001 1000 --> 24 を返します。

右端または左端からはみ出した部分は削除されます。

[例]

% expr 7 >> 1   ---(1)
3

% set n1 [expr 0xff00000000000000 << 1]   ---(2)
36749372959343247360

% format %x $n1
fe00000000000000

[説明]

(1)右端からはみ出した場合。

 7 : 0111
       ↓ >> 1桁、右へシフトさせる。
     0011 --> 3 を返します。

(2)左端からはみ出した場合。

FF(16進数) : 
 F  F
1111 1111 0000 0000 0000 0000 0000 0000
0000 0000 0000 0000 0000 0000 0000 0000
↓ << 左へ1桁シフトさせると、
FE(16進数) :  F  E 1111 1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 --> 1桁、左へシフトすると
FE00000000000000になります。

formatコマンドの %x は $n1を16進数に変換します。


この記事以外のexprコマンドの使い方は、必要に応じて以下の記事を参考にしてください。

コメント

タイトルとURLをコピーしました