Juliaで行こう! 〜ビット演算子編〜

事始め

JuliaのOnline Manualを読んでおりまして。その流れで、いろいろと書いておくのもよいかもしれないと思いまして。
つらつらと始めようか、と。ゴールは定めていないので、それなりに(笑)
で、読んでいて、急に、気になったのが「ビット演算子」というお話。

Julia Version on Fedora 28

今後、何度も記載することになるのでしょうが、Fedora 28に標準搭載されているのは、0.6.3というVersionです。
Fedora 29(2018-10-30 Release予定)には、0.7.01.0.0のどちらかが搭載されると思います。ちなみに、Juliaの最新Stableは1.0.0です。(1.1.0は開発版)
従って、以降のお話は、しばらく、0.6.3でのお話になります。

ビット演算子とは?

まずは、気になったビット演算の例をば。(結果的には、勘違いきっかけ。恋のようなもの)

 julia> 1 & 1
 1
 julia> 1 & 0
 0
 julia> 10 & 10
 10
 julia> 11 & 11
 11
 julia> 11 & 12 
 8

Interpreterモードにて、お試しをしてみました。へぇーなるほど、と。
ただ、我々は普段10進数の世界にて生存していることから、1112の積である8に疑問が湧きます。
というか、湧いてしまったのですね。「ビット演算子」という項目なのに。

すわ、ビット演算

つまるところ、ビット演算とは、10進数の世界ではなく、非常にコンピュータに優しい2進数の世界の演算ということになります。
例えば、10進数にて、29という数字は、

29 = 2 * 10^1 + 9 * 10^0

ではありますが、2進数では、

> 29 = (1 * 2^4) + (1 * 2^3) + (1 * 2^2) + (1 * 2^0)

ということになります。括弧は見やすくするための措置なので、意味はありません。
もう少し詳しく書くなら、

29 = (1 * 2^4) + (1 * 2^3) + (1 * 2^2) + (0 * 2^1) + (1 * 2^0)

これを10進数と同じような表記にするなら、

29 => 0001 1101

となるでしょうか。表記上わかりやすくするために、上位3ビット(桁)分を追加し、 4ビット毎に見やすくしています。

8b'00011101

なんていう書き方もあったりします。頭の「8」は桁数を示しています。

桁(上位ビット)

10進数は、0〜9の数字を用いて、表現を行っています。ある桁において、その数字が7である時、1という数字が加算されると、8となります。(0は9より大きいというような数学的な事象はひとまず側においておきます(笑))
では、ある桁が9であった時、1という数字が加算されると、9より大きな数字は、その桁においては表現ができません。そこで、桁を一つ増やし、より大きな数字を表現させています。代わりに、当該の桁の数字を最小値(0)に戻しているのです。

8 + 1 => 08 + 01 => 09
9 + 1 => 09 + 01 => 10

99に1を加算すると、まず、1の桁を0にすると共に、10の桁に1を加算します。
ですが、10の桁の元の数字も9であるため、10の桁を0にすると共に、100の桁を0から1に変更する必要がでてきます。

99 + 1 => 099 + 001 => 100

2進数

10進数が0〜9を用いて表現するのであれば、2進数は0〜1を用いて表現することになります。
言ってしまえば、各桁の最大値は1であり、22という数字はその世界(2進数の世界)には存在しないということです。
つまり、1に1が加わった場合、

1 + 1 = 10
01 + 01 = 10

ということになります。結果が10となっているのは、先の「桁」の考え方を用いると理解できると思います。
2進数の10は10進数では2です。

そして戻る

「ビット演算子」で使用しているのは「&」。つまり、「積」です。加えて、「ビット」ですから、「各ビット」、つまり、「各桁」毎の処理を行っています。
「&」の左を「集合A」、右を「集合B」とした場合、「&」は、「集合A」と「集合B」が重なる部分のみが「真」、つまり、「1」であり、それ以外は「0」ということを意味しています。(「和」の場合は、「集合A」と「集合B」が共に「0」以外は全て「1」となります)

1 & 1 => 1
1 & 0 => 0
0 & 1 => 0
0 & 0 => 0

従って、

11 & 11 => 11

は、各ビット毎の積はそれぞれ「1」という結果を出しますので、「11」ということなります。
では、

11 & 12 => 8

は、どういうことになるかと言えば、

11 & 12 => 1011 & 1100 => 1000

となり、

1000 => (1 * 2^3) + (0 * 2^2) + (0 * 2^1) + (0 * 2^0) => 8

という結果を得ることになります。

でもでもだって

ただ、最初の疑念は、「10&10」「11&11」の結果がそれぞれ「10」と「11」であるのに、「11&12」の結果が「8」であるか、というところ。
「1000」と表現してくれれば、と思うのですが、最初の2つは共に2進同士であることがわかっているために、結果は2進表現。
最後は2進と10進の積であるため、「11」も2進ではなく、10進であるとなり、結果は10進ということになっているということを、直感的に(自分が)理解し切れなかったというお話で。
えぇ、きちんと、Manual読めばいいのだと思います、きっと。
(検証をPythonでやったというのは内緒の話。結果は当然のことながら一緒でしたけどね…)

コメント

このブログの人気の投稿

Tabulatorで行こう! 〜ダイバー編〜

Tabulatorで行こう! 〜違うじゃん編〜

Fedoraで行こう! 〜音声合成pyttsx3編〜