はじめに
チェリー本の2章2.9.2のビット演算のところ、サラっと解説してありますけど、n進数の知識が曖昧な人が見ると結構理解が難しいと思うんですよね。特に次の部分。
# 以下はビット演算を行う例です(結果を2進数で確認できるように、to_s(2)を呼び出しています)。
(~0b1010).to_s(2) #=> "-1011"
“~”(チルダ)
はビット反転を表すようです。
ビット反転ってのは単純に2進数の01を反転させる操作なんで
(~0b1010).to_s(2)
ときたら、"0101"
になると思うじゃないですか!
しかし、irb上で実際に返ってくるのは**"-1011"
**とのこと。
初めてこれを見たときには頭を抱えましたが、色々調べてみる中でどういうことなのか理解しましたので、ここに記録を残しておきます。
ちなみに前提として、n進数に関する基本的な知識が必要です(基本情報処理技術者試験の参考書とかで勉強できます。)
(~0b1010)
まず、(~0b1010).to_s(2)
の (~0b1010)
の部分ですが
こちら側は4桁の2進数を入力したつもりでも、コンピュータ上だと実際には0...0001010
のような4桁以上のビット数の値として取り扱われていることを理解している必要があります。
それを踏まえた上で “~”(チルダ)
に従い 0...0001010
をビット反転すると、1...1110101
となります。
(※ 実際には irb 上だと0b表記の2進数は自動的に10進数に変換されるので、(~0b1010)
は-11
が返ってきます。しかし結局は-11 == 1...1110101
ですし、ここでは2進数として考えたほうが都合が良いのでそうします。)
つまり(~0b1010).to_s(2)
という式は
1...1110101
に対してto_s(2)
メソッドが呼ばれていると考えられますね。
to_s(2)メソッド
ここでもう一つ大事なポイントは、to_s(2)
メソッドが
正負を符号ビットで表さない、つまり負の数をマイナス記号で表す2進数として数値を文字列に変換する点にあります。もっと別の言い回しがなかったかなと考えております。
そして1...1110101
は2の補数表現(負の数)であります。
つまり今回の場合、to_s(2)
メソッドは 1...1110101
を -XXXX (Xには0か1が入る)
のようにマイナス記号がついた4ビットの2進数になるように変換します。
要は 1...1110101
を一度正の数に変換したあとマイナス記号をつける、という感じになりますね。
よって "-1011"
1...1110101
は2の補数表現(負の数)ですが、これに対して更に2の補数を求める操作を行えば、裏返って正の数になります。0...0001011
です。
そんで5桁目以降の0を省いて、元は負の数ですのでマイナス記号をつけ、さいごに文字列に変換してやれば....
_人人人人人人人人人_
> "-1011" <
 ̄Y^Y^Y^Y^Y^Y^Y^Y ̄
以上です
以上です。なんか間違ってる部分あったらご指摘お願いします。