LoginSignup
3
1

More than 3 years have passed since last update.

【チェリー本】なぜ (~0b1010).to_s(2) #=> "-1011" なのか

Last updated at Posted at 2020-02-09

はじめに

チェリー本の2章2.9.2のビット演算のところ、サラっと解説してありますけど、n進数の知識が曖昧な人が見ると結構理解が難しいと思うんですよね。特に次の部分。

『プロを目指す人のためのRuby入門』より抜粋
# 以下はビット演算を行う例です(結果を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 ̄

以上です

以上です。なんか間違ってる部分あったらご指摘お願いします。

3
1
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1