最近は生徒さんからの質問も増えてきて、先日は電池の酸化還元反応について問われました。まあ、プログラミングとは直接関係ありませんが。
今回はビット演算の話です。
コンピュータの内部では2進数が使われています。
すなわち0と1の2種類の数字を使って計算しています。
2進数で表示したときの1桁が1ビットです。8ビットは1バイトと呼ばれます。
情報の最小単位がビットで、情報の基本単位がバイトです。
通常のプログラミングではあまり行われなくなってきましたが、ビット単位で演算をすることができます。
ここではProcessingを使ってビット演算を試してみましょう。
binary()で2進数表示ができます。
■AND
両方のビットが1のときのみ結果が1になります。
例えば、aに123を、bに456を代入して a AND b の演算を行うと下記のような結果が得られます。
a 123 00000000000000000000000001111011
b 456 00000000000000000000000111001000
a AND b 00000000000000000000000001001000
■OR
いずれかのビットが1なら結果が1になります。
例えば、
a 123 00000000000000000000000001111011
b 456 00000000000000000000000111001000
a OR b 00000000000000000000000111111011
といった具合です。
■XOR
両方のビットが異なるときに1 になります。
例えば、
a 123 00000000000000000000000001111011
b 456 00000000000000000000000111001000
a XOR b 00000000000000000000000110110011
のようになります。
■左シフト
1ビット左にシフトすると2倍することができます。
例えば、nに123を代入して左シフトしてみます。
n 123 00000000000000000000000001111011
n << 1 246 00000000000000000000000011110110
nは246になりました。
■右シフト
1ビット右にシフトすると2で割ることができます。
例えば、先ほどのnを右シフトしてみます。
n 246 00000000000000000000000011110110
n >> 1 123 00000000000000000000000001111011
nは123になりました。
■1の補数
2進数の場合、補数は2つあります。1の補数と2の補数です。
元の数に1の補数を補うと2進数の最大値になります。
1の補数はビットを反転することで得られます。
例えば、mに123を代入してビット反転してみます。
m 123 00000000000000000000000001111011
~m -124 11111111111111111111111110000100
■2の補数
負の数を表現する方法です。1の補数に1を加えることで得られます。
2の補数を元の数に補うと桁が上がります。
そして、桁上がりしたビットは無視されるため0になります。
補ったら0になるということは元の数の対となる負数と言えるわけです。
最上位ビットは符号ビットと呼ばれます。
例えば、先ほどのmの2の補数を求めてみましょう。
m 123 00000000000000000000000001111011
~m+1 -123 11111111111111111111111110000101
負の数 -123 が得られました。
以上をProcessingのコードにすると以下のようになります。
void setup() {
noLoop();
}
void draw() {
// bitwise AND
// 両方のビットが1のときのみ結果が1
println("bitwise AND");
int a = 123;
int b = 456;
println("a ", a, binary(a));
println("b ", b, binary(b));
int c = a & b;
println("a AND b", binary(c));
println();
// bitwise OR
// いずれかのビットが1なら結果が1
println("bitwise OR");
println("a ", a, binary(a));
println("b ", b, binary(b));
c = a | b;
println("a OR b", binary(c));
println();
// bit XOR
// 両方のビットが異なるときに1
println("bit XOR");
println("a ", a, binary(a));
println("b ", b, binary(b));
c = a^b;
println("a XOR b", binary(c));
println();
// bit left shift
// 2倍する
println("bit left shift");
int n = 123;
println("n ", n, binary(n));
n = n << 1;
println("n << 1", n, binary(n));
println();
// bit left shift
// 2で割る
println("bit right shift");
println("n ", n, binary(n));
n = n >> 1;
println("n >> 1", n, binary(n));
println();
// bit INVERT 1の補数
// 1の補数を補うと2進数の最大値になる
println("bit INVERT");
int m = 123;
println("m ", m, binary(m));
m = ~m;
println("~m ", m, binary(m));
println();
// bit INVERT 2の補数
// 負の数を表現する方法
// 2の補数を補うと桁が上がる
// 桁上がりしたビットは無視されるため0になる
// 補ったら0になるということは元の数の対となる負数と言える
// 最上位ビットは符号ビット
println("bit INVERT + 1");
m = 123;
println("m ", m, binary(m));
m = ~m + 1;
println("~m + 1", m, binary(m));
}


