この章の概要です。
我々は普段の生活で、0~9 までの 10種類の数を使って、数を表記しています。これは、10進法と呼ばれる表記方法です。10進法で表記された数を、10進数と呼びます。
10進法では、0 から順番に数を増やしていったとき、10 のところで桁が増えます。これが「10進」という言葉の意味合いで、10 になると進む(桁が変わる)ということです。
10進法では、数を 10 のべき乗と、10種類の数字(0~9) を使って表現します。たとえば、345 という数は、「102 * 3 + 101 * 4 + 100 * 5」と考えればよいです(ある正の数の 0乗はつねに 1 です)。
小数点以下の値も同様に考えられます。たとえば、345.67 であれば、「102 * 3 + 101 * 4 + 100 * 5 + 10-1 * 6 + 10-2 * 7」のことです。10-1 とは、10分の1 (0.1) のこと、10-2 とは 100分の1 (0.01) のことです。
先ほどの 10進数の話の中で、「10」のべき乗とか、「10」種類の数字といったように、10 という値が現れました。この数を、基数といいます。
基数は 10以外であっても構いません。プログラミングの世界では、基数が 2、8、10、16 の数がよく用いられます。この先の項で、順番に見ていきます。
なお、基数を n と表現するとき、表現方法を n進法といいます。また、n進法で表記された数を n進数といいます。
プログラミングでは、2進数 (binary number) が非常に重要です。なぜなら、コンピュータは情報を 2進数で表現するからです。日頃、コンピュータを利用していてもそうは見えませんが、内部では 2進数が、人間に見える部分には(基本的に)10進数が使われているのです。
2進数の数値は、0、1、10、11、100 … のように増えていきます。つまり、2 のところで桁が変わります。
10進数のところで見たように、基数が 2 であることの意味は、数を 2 のべき乗と、2種類の数字(0~1) を使って表現するということです。たとえば、2進数の 1001 という数は、「23 * 1 + 22 * 0 + 21 * 0 + 20 * 1」であることを意味しています。つまり「8 + 0 + 0 + 1」なので「9」のことです。2進法で表記した「1001」と 10進法で表記した「9」が同じ値であることを示しています。
なお、2進数の 1桁分のデータを、ビットという単位で呼びます。
ビットという単位とともに、バイトという単位もよく目にするはずです。ほとんどの場合、1バイトは 8ビットと同じことです。
最後に、2進数の「1000」は「せん」とは呼ばないようにしましょう。「千」はあくまで 10進数の世界の「1000」です。2進数の「1000」は、10進数では「8」なので、「いちぜろぜろぜろ」と呼ぶのが確実です。
基数が n の数を、異なる基数 m の数に変換する方法は知っておくべきです。まずは、10進数を 2進数に変換する方法を見てみましょう。
10進数を 2進数に変換するには、
たとえば、10進数の 93 なら、
2)93
2)46・・・1
2)23・・・0
2)11・・・1
2) 5・・・1
2) 2・・・1
2) 1・・・0
0・・・1
のように計算を行い、書き出された余りの部分を逆順に読み取ります。結果は「1011101」です。
この計算方法ですが、元になる数が 10進数でさえあれば、変換先が何進数であっても同じです。たとえば、5進数に変換するのなら、5 で割ることを繰り返します。
5)93
5)18・・・3
5) 3・・・3
0・・・3
結果は「333」です。5進数なんて言われてもピンとこないですが…。
次に、2進数から 10進数へ変換する方法ですが、これは「2進数」のところで見たとおりです。2進数の各桁は「2x * (0 または 1)」のことなので、ここから計算できます。
たとえば 2進数の「1011101」という数は、「26 * 1 + 25 * 0 + 24 * 1 + 23 * 1 + 22 * 1 + 21 * 0 + 20 * 1」です。したがって「64 + 16 + 8 + 4 + 1」ですから、その結果は 93 です。
このようにして、2進数を 10進数に変換できます。
この方法は、10進数へ変換するのであれば、変換元が何進数であっても共通して使えます。前の項と同様に、5進数で実験しましょう。5進数の「333」を 10進数に変換します。
5進数の「333」は、「52 * 3 + 51 * 3 + 50 * 3」ですから、「75 + 15 + 3」となり、その結果は 93 です。
8進数は、8進法で表記された数です。8進法では、「0~7」までの合計 8種類の数字で数を表記します。7 の次で桁が増えるので、「…6、7、10、11…」と増えていきます。
16進法では、「0~9」と「A~F」の合計 16種類の数字と文字を使って表記します。アルファベットの部分は、大文字でも小文字でも構いません。16進法で表記された数を、16進数と呼びます。
16進法では、「…7、8、9」と増えていった数は、次に「A、B、C、D、E、F」と増えます。10進数でいえば、A が 10、B が 11、F が 15 を意味しています。F の次で桁が増えて、16進数の「10」になります。
ここまでに、10進数から n進数の変換と、n進数から 10進数の変換だけを紹介しています。しかし、この2つさえ知っていれば、n進数と m進数の変換はつねに行えるはずです。たとえば、4進数を 7進数に変換したいとすれば、
のように、2つの過程を経れば良いのです。
試しに、2進数の 1101100 を 16進数に変換してみましょう。
まずは、10進数に変換します。これは、次の計算式で行えます。
「26 * 1 + 25 * 1 + 24 * 0 + 23 * 1 + 22 * 1 + 21 * 0 + 20 * 0」となり、「64 + 32 + 8 + 4」となるので、結果は 108 です。
この段階で、10進数の 108 が得られました。ここからさらに、16進数への変換作業を行います。10進数からの変換の場合は、変換後の基数で割る作業を繰り返し、余りを逆方向に読み取っていくのでした。
16)108
16) 6・・・12
0・・・6
余りを逆方向から読むと「6 12」ですが、16進数なので「12」は「C」です。したがって、結果は「6C」です。
こうして、2進数の 1101100 を、16進数の 6C に変換できます。
よく登場する 2・8・10・16進数の対応表を載せておきます。
2進数 | 8進数 | 10進数 | 16進数 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 |
10 | 2 | 2 | 2 |
11 | 3 | 3 | 3 |
100 | 4 | 4 | 4 |
101 | 5 | 5 | 5 |
110 | 6 | 6 | 6 |
111 | 7 | 7 | 7 |
1000 | 10 | 8 | 8 |
1001 | 11 | 9 | 9 |
1010 | 12 | 10 | A |
1011 | 13 | 11 | B |
1100 | 14 | 12 | C |
1101 | 15 | 13 | D |
1110 | 16 | 14 | E |
1111 | 17 | 15 | F |
相互の変換方法を理解していれば、これを丸暗記する必要はありませんが、長い間、これらの数に親しんでいると、ある程度は自然に暗記できると思います。
Windows の標準ツールである「電卓」を使うと、2進数、8進数、10進数、16進数のあいだでの変換を簡単に行えます。
今度は負の整数を表現する方法について確認しましょう。コンピュータでは 2進数を用いるということなので、ここでは 2進数の例を挙げます。
2進数で負の整数を表現するには、3つのよく知られた方法があります。
ここでは、圧倒的によく使われている 2の補数表現という手法を取り上げます。
2の補数とは、n桁の 2進数で表される整数 x があるとき、「x + y = 2n」を満たす y のことです。
2の補数表現では、正の整数 x の符号を変えた -x を表現するために、x の 2の補数を使う手法です。なお、2の補数表現では、最上位のビットが 0 のときは正の数であり、1 のときは負の数であるものとします。
たとえば、「0111」という 4桁の 2進数があるとします。最上位が 0 なので、これは正の数であり、+7 のことです。「0111」の 2の補数は、先ほどの式のとおり「0111 + y = 10000」となる y のことですが、この y の値を -7 を表現するものして扱います。
計算してみると「10000 - 0111」なので、y は「1001」であることが分かります。よって「0111」が +7、「1001」が -7 です。
このように普通に計算しても良いのですが、2の補数は、以下の手順で簡単に求められます。
「0111」を例に取ります。各ビットを反転すると「1000」です。ここに +1 すると「1001」が得られます。先ほど、普通に計算した結果と一致しました。
【上級】ちなみに、手順1で止めると 1の補数になっています。1の補数表現を使う世界では、「0111」が +7 を、「1000」が -7 を表します。
【上級】符号と絶対値による表現を使う世界では、最上位のビットを符号の表現に使い、残りのビットで絶対値を表現します。符号のビットが 0 ならば正、1 ならば負とします。この表現では、「0111」が +7、「1111」が -7 を表しています。
逆の操作をすれば、負の整数を正の整数に変換できます。つまり、次の手順を踏みます。
この方法を知っておけば、最上位ビットが 1 になっている負の 2進整数が与えられたとき、それが 10進数でいくつのことなのか分かります。たとえば「1100」で試してみます。最上位ビットを見れば負数なのは明らかですが、具体的な数は単純には分かりません。
「0110」は +6 のことなので、元の数「1100」は -6 のことだったと分かります。
2の補数表現では、負の数の方が、正の数よりも表現できる値が1つ多いという特徴があります。
たとえば、4桁の 2進数において表現できる最大の正の数は「0111」です。正の数であるためには、最上位ビットは 0 でなければならず、残りのビットがすべて 1 のときが最大値です。
一方、最小の負の数は「1000」です。2の補数を求める過程で各ビットを反転するので、最上位ビット以外には 0 が並んでいる状態が最小です。
ここで「1000」は -8 のことなのですが、+8 は表現できません。負の整数を正の整数に変換する手順を実行してみると、以下のようになります。
このように「1000」は「1000」に戻ってしまいます。最上位ビットが 1 であるため、これは負の数を表しており、-8 に対応する正の数(+8) は表現できないということが分かります。
したがって、2の補数表現を使う 4桁の 2進数の世界で表現できる値の範囲は、-8~+7 です。これは桁数が変わっても同じで、つねに負数の側の表現力が 1つ分多くなります。
【上級】1の補数表現や、符号と絶対値による表現では、正と負とで表現範囲に違いはありません。その代わり、0 を表現する方法が2通りあるという別の特徴があります(原理上、+0 と -0 があり得る)。
’2019/8/5 C言語編第18章から切り出してくる形で新規作成。
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |