コンピュータサイエンス編 - 基数 | Programming Place Plus

トップページコンピュータサイエンス編

この章の概要

この章の概要です。


10進数

我々は普段の生活で、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進数

プログラミングでは、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」なので、「いちぜろぜろぜろ」と呼ぶのが確実です。

10進数を n進数へ変換する

基数が n の数を、異なる基数 m の数に変換する方法は知っておくべきです。まずは、10進数を 2進数に変換する方法を見てみましょう。

10進数を 2進数に変換するには、

  1. 元の数を 2 で割り、その余りを書き出す
  2. 元の数が 0 になるまで、(1) を繰り返す
  3. 書き出しておいた余りを、逆順に読み取ると、それが 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進数なんて言われてもピンとこないですが…。

n進数を 10進数へ変換する

次に、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進法で表記された数です。8進法では、「0~7」までの合計 8種類の数字で数を表記します。7 の次で桁が増えるので、「…6、7、10、11…」と増えていきます。

16進数

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」になります。

n進数から m進数へ変換する

ここまでに、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)

Windows の標準ツールである「電卓」を使うと、2進数、8進数、10進数、16進数のあいだでの変換を簡単に行えます。

方法は、「Windows編電卓で基数変換する」を参照してください。

2進数の負の整数

今度は負の整数を表現する方法について確認しましょう。コンピュータでは 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の補数は、以下の手順で簡単に求められます

  1. 各ビットを反転する (0 は 1 に、1 は 0 に)
  2. +1 する (桁が溢れた部分は無視する)

「0111」を例に取ります。各ビットを反転すると「1000」です。ここに +1 すると「1001」が得られます。先ほど、普通に計算した結果と一致しました。

【上級】ちなみに、手順1で止めると 1の補数になっています。1の補数表現を使う世界では、「0111」が +7 を、「1000」が -7 を表します。

【上級】符号と絶対値による表現を使う世界では、最上位のビットを符号の表現に使い、残りのビットで絶対値を表現します。符号のビットが 0 ならば正、1 ならば負とします。この表現では、「0111」が +7、「1111」が -7 を表しています。

逆の操作をすれば、負の整数を正の整数に変換できます。つまり、次の手順を踏みます。

  1. -1 する
  2. 各ビットを反転する (0 は 1 に、1 は 0 に)

この方法を知っておけば、最上位ビットが 1 になっている負の 2進整数が与えられたとき、それが 10進数でいくつのことなのか分かります。たとえば「1100」で試してみます。最上位ビットを見れば負数なのは明らかですが、具体的な数は単純には分かりません。

  1. -1 して「1001」
  2. 各ビットを反転して「0110」

「0110」は +6 のことなので、元の数「1100」は -6 のことだったと分かります。

2の補数表現では、負の数の方が、正の数よりも表現できる値が1つ多いという特徴があります。

たとえば、4桁の 2進数において表現できる最大の正の数は「0111」です。正の数であるためには、最上位ビットは 0 でなければならず、残りのビットがすべて 1 のときが最大値です。

一方、最小の負の数は「1000」です。2の補数を求める過程で各ビットを反転するので、最上位ビット以外には 0 が並んでいる状態が最小です。

ここで「1000」は -8 のことなのですが、+8 は表現できません。負の整数を正の整数に変換する手順を実行してみると、以下のようになります。

  1. -1 して「0111」
  2. 各ビットを反転して「1000」

このように「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で書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る