こんにちは、MSKです。
今回は数字の表し方であるn進数について解説します。
プログラミングを行う上でも大切な考え方になります。
数字の表し方について考えてみよう
普段使っている数字 ~ 10進数 ~
普段僕たちは次のように数字を数えます。
1,2,3,4,5,6,7,8,9,10,11,12,13, … , 98,99,100,101, …
この数字の並びを見て思うことの1つに9の次で桁が上がっているということです。
1つの桁に出てくる数字は$0,1,2,3,4,5,6,7,8,9$の10個です。
このように10で桁上がりをしているような表記を10進数表記といいます。
0と1の世界 ~ 2進数 ~
2で桁上がりする表記方法は有名ですね。
2になると次の桁に進む数字の表記方法を2進数表記と言います。
2進数では各桁に0と1しか現れません。
コンピューターは内部で2進数を使用しています。
なぜ2進数が使われるのかを簡単に説明するとコンピューターの内部は電子回路の集まりになっていますが、その電子回路では電圧がかかっているか・かかっていないかの2つの状態があります。
電圧がかかっている状態を1、かかっていない状態を0とできるので、コンピューターでは2進数が扱いやすいのです。
10進数 → 2進数と対応させてみたいと思います。
0 → 0
1 → 1
2 → 10
3 → 11
4 → 100
2進数であることを強調したい場合は通常0bを数値の先頭につけます。
例えば、0b1001001のような感じです。
コンピューターと相性がよい ~ 8進数,16進数 ~
2進数と同じように8で桁上がりする表記を8進数表記、16で桁上がりする表記を16進数表記といいます。
16進数の場合、9の次は次のように並びます。
A、B、C、D、E、F
2進数のときと同じように10進数と対応をつけたいと思います。
①10進数 → 8進数
6 → 6
7 → 7
8 → 10
9 → 11
・・・・・
63 → 77
64 → 100
65 → 101
②10進数 → 16進数
9 → 9
10 → A
11 → B
12 → C
13 → D
14 → E
15 → F
16 → 10
17 → 11
・・・・・
254 → FE
255 → FF
256 → 100
8進数であることを強調したい場合は通常0oを、16進数であることを強調したい場合は通常0xを数値の先頭につけます。
例えば、0o7654321、0xABCD01のような感じです。
※なぜ、2進数は0b、8進数は0o、16進数は0xなのかというと、Binary(英語で2進数)、Octal(英語で8進数)、Hexadecimal(英語で16進数)の頭文字からきています。
8進数・16進数はコンピューターと相性が良いです。
上でコンピューターでは2進数が使われていると書きました。
8進数の一桁を2進数でみるとちょうど3桁分になっています。
8進数の一桁 = 0b000 ~ 0b111(=7)
昔のコンピューターは2進数12桁、または24桁で処理されるものが多く、3桁の表記を持つ8進数との相性が良いとされていました。
16進数の一桁も2進数でみるとちょうど4桁分になっています。
16進数の一桁 = 0b0000 ~ 0b1111(=15)
現在のコンピューターは2進数の32桁、または64桁で処理されるものが多く、4桁の表記を持つ16進数と相性が良いです。
ビット・バイトやコンピュータサイエンスでよく使われる単位について
1ビット(bit)は2進数の1桁のことを言います。
例えば、0b110は3ビット持っています。
8ビットを1つの単位とみなしたものがバイト(byte)という単位になります。
コンピューターの世界でよく目にするバイトはこのことです。
1バイトで0から255の256個の表現ができます。
コンピューターサイエンスでよく使われる単位をまとめておきます。
ピコ(p) = 10^{-12}
ナノ(n) = 10^{-9}
マイクロ(μ) = 10^{-6}
ミリ(m) = 10^{-3}
キロ(k) = 10^3 \fallingdotseq 2^{10}
メガ(M) = 10^6 \fallingdotseq 2^{20}
ギガ(G) = 10^9 \fallingdotseq 2^{30}
テラ(T) = 10^{12} \fallingdotseq 2^{40}
n進数
今まで見てきたことからn進数はnで桁上がりする表記です。
各桁に出てくる数字は0からn-1までです。
n進数表記のnを基数といいます。
各桁に出てくる数値は0からn-1までのn個なので、基数とは各桁に出てくる数値の個数とも言えます。
基数変換
ある基数の表示から別の基数の表記へ変換することを考えていきたいと思います。
10進数をもう一度眺めてみる
10進数で次の数字を考えてみます。
1234.567
これは次にように表記できます。
1 \times 10^3 +2 \times 10^2 +3 \times 10^1 +4 \times 10^0 +5 \times 10^{-1} +6 \times 10^{-2} +7 \times 10^{-3}
もとの数字は(各桁の数字) \times 10^{~}を全部足したものになっています。
~は整数部分では桁数-1で、小数部分では小数第p位だとすると-pとなります。
これはn進数で表したときも同じように表記でき、10^{~}となっている部分が(基数)^{~}となります。
(実際、10進数の場合もこのようになっていますね)
この(基数)^{~}をその桁の重みといいます。
n進数で表された数値を10進数に変換する際はこの内容を使用します。
具体的に見ていきましょう。
2進数から10進数に変換してみよう
0b101101.101を考えます。
上で述べたことから、次のように表せます。
1 \times 2^5 +1 \times 2^3 +1 \times 2^2 +1 \times 2^0 +1\times 2^{-1} +1 \times 2^{-3} = 32 + 8 + 4 + 1 + 0.5 + 0.125 = 45.625
問題も書いておきたいと思います。
次の2進数を10進数に変換してください。
(1) 0b1011.011
(2) 0b10001.11
8進数・16進数から10進数に変換してみよう
まずは8進数から10進数に変換します。
0o137.246を考えます。
2進数のときと同様に
0o137.246 \\ =1 \times 8^2 +3 \times 8^1 +7 \times 8^0 +2 \times 8^{-1} +4 \times 8^{-2} +6 \times 8^{-3} \\ = 64 + 24 + 7 + 0.25 + 0.0625 + 0.01171875 \\ =95.32421875
次の8進数を10進数に変換してください。
(1) 0o37.117
(2) 0o2167.62
次に16進数から10進数へ変換します。
0xA1C.6E \\ = 10 \times 16^2 +1 \times 16^1 +12 \times 16^0 +6 \times 16^{-1} +14 \times 16^{-2} \\ = 2560 + 16 + 12 + 0.375 + 0.0546875 \\ = 2588.4296875
次の16進数を10進数に変換してください。
(1) 0xF2.A7
(2) 0x3FA.F2
10進数からn進数に変換してみよう
10進数からn進数に変換する手順は以下になります。
- 10進数表示された数値の整数部分と少数部分に分けます。
- 整数部分は基数で割り、商と余りを出します。
- その商をまた基数で割り、商と余りを出します。
これを商が0になるまで行います。 - 出てきた余りを出てきた順番とは反対に並べると整数部分のn進数表記になります。
- 少数部分は基数をかけて出てきた数値の整数部分を取り出します。
- 残った数値にまた基数をかけて、同じことを繰り返します。
- 少数部分がなくなったらそこまで出てきた整数部分を順番に並べると少数部分のn進数表記になります。
- 整数部分と少数部分を組み合わせて、全体のn進数表記ができあがります。
例で見ていきたいと思います。
34.8125を2進数表記にしたいと思います。
- 整数部分は34、少数部分は0.8125です。
- 34を基数の2で割ります。
34 \div 2 = 17 余り 0 - 17 \div 2 = 8 余り 1
8 \div 2 = 4 余り 0
4 \div 2 = 2 余り 0
2 \div 2 = 1 余り 0
1 \div 2 = 0 余り 1 - 出てきた余りを出てきた順番と逆に並べると100010
- 少数部分の0.8125に基数の2をかけます。
0.8125 \times 2 = 1.625 整数部分 1 - 0.625 \times 2 = 1.25 整数部分 1
0.25 \times 2 = 0.5 整数部分 0
0.5 \times 2 = 1.0 整数部分 1 - 出てきた整数部分を順番に並べると1101
- 34.8125を2進数に変換すると100010.1101となります。
(1) 10進数の13.75を2進数表記してください。
(2) 10進数の34.8125を8進数表記してください。
(2) 10進数の34.8125を16進数表記してください。
2進数と8進数・16進数の間の変換
2進数から8進数・16進数の変換は簡単です。
上で8進数の一桁は2進数の3桁、16進数の一桁は2進数の4桁になると書きました。
これを使います。
2進数表記の0b1010.10を考えます。
8進数に変換する場合は整数部分と少数部分に分けて、それぞれ3桁で区切ります。
整数部分1010は、001と010です。
少数部分は100です。
これらをそれぞれ8進数に変換します。
001=1
010 = 2
100 = 4
あとはこれらを順番に並べて、12.4が8進数に変換した表記になります。
16進数もほとんど同じで8進数では3桁区切りだったところを4桁区切りにします。
整数部分は1010、少数部分は1000です。
これらを16進数に変換します。
1010 = A
1000 = 8
これらを並べるとA.8になり、これが0b1010.10を16進数表記したものになります。
次の2進数を8進数と16進数の表記にしてください。
(1) 0b1001.011
(2) 0b110.1011
8進数・16進数から2進数への変換も簡単です。
2進数から8進数・16進数への変換と逆を行います。
8進数・16進数の各桁の数値を2進数にして、並べるだけです。
(1) 0o64.71を2進数表記します。
6 = 0b110
4 = 0b100
7 = 0b111
1 = 0b001
なので、0o64.71は2進数で0b110100.111001とかけます。
(2) 0xD71.BFを2進数表記します。
D = 0b1101
7 = 0b0111
1 = 0b0001
B = 0b1011
F = 0b1111
なので、0xD71.BFは2進数で0b110101110001.10111111とかけます。
次を2進数表記にしてください。
(1) 0o32.65
(2) 0x4A.C9
まとめ
n進数、特に2進数、8進数、16進数について表記の方法や基数変換をたくさんの例を使って解説してきました。
基本情報技術者試験を受ける人は知っておかないといけない知識になります。
また、組み込み系のエンジニアを目指している方は2進数、16進数を扱えることは必須になります。
以上、「n進数を理解しよう!」でした。
最後までご覧頂き、ありがとうございます。
問題の回答
(1) 0b1011.011 = 1 \times 2^3 + 1 \times 2^1 +1 \times 2^0 +1 \times 2^{-2} +1 \times 2^{-3} \\
= 8 + 2 + 1 + 0.25 + 0.125 \\
= 11.375
(2) 0b10001.11 = 1 \times 2^4 +1 \times 2^0 +1 \times 2^{-1} +1 \times 2^{-2} \\
= 16 + 1 + 0.5 + 0.25 \\
= 17.75
(1) 0o37.117 = 3 \times 8^1 +7 \times 8^0 +1 \times 8^{-1} +1 \times 8^{-2} +7 \times 8^{-3} \\ = 24 + 7 + 0.125 + 0.015625 + 0.013671875 \\ = 31.154296875
(2) 0o2167.62 = 2 \times 8^3 +1 \times 8^2 +6 \times 8^1 +7 \times 8^0 +6 \times 8^{-1} +2 \times 8^{-2} \\ = 1024 + 64 + 48 + 7 + 0.75 + 0.03125 \\ = 1143.78125
(1) 0xF2.A7 = 15 \times 16^1 +2 \times 16^0 +10 \times 16^{-1} +7 \times 16^{-2}\\ = 240 + 2 + 0.625 + 0.02734375 \\ = 242.65234375
(2) 0x3FA.F2 =3 \times 16^2 +15 \times 16^1 +10 \times 16^0 +15 \times 16^{-1} +2 \times 16^{-2} \\ = 768 + 240 + 10 + 0.9375 + 0.0078125 \\ =1018.9453125
(1)
13.75の整数部分は13、少数部分は0.75です。
13 \div 2 = 6 余り 1
6 \div 2 = 3 余り 0
3 \div 2 = 1 余り 1
1 \div 2 = 0 余り 1
一方、
0.75 \times 2 = 1.5 整数部分 1
0.5 \times 2 = 1.0 整数部分 1
以上より、13.75の2進数表記は1101.11となります。
(2)
整数部分の計算から行います。
34 \div 8 = 4 余り 2
4 \div 8 = 0 余り 4
次に少数部分の計算を行います。
0.8125 \times 8 = 6.5 整数部分は6
0.5 \times 8 = 4.0 整数部分は4
以上より、34.8125の8進数表記は42.64となります。
(3)
整数部分の計算から行います。
34 \div 16 = 2 余り 2
2 \div 16 = 0 余り 2
次に少数部分の計算を行います。
0.8125 \times 16 = 13.0 整数部分は13=D
以上より、34.8125の16進数表記は22.Dとなります。
(1)
0b1001.011
8進数の場合は3桁で区切っていきます。
001と001、011となります。
それぞれを8進数にすると、001=1、001=1、011=3なので、
0b1001.011を8進数表記すると11.3となります。
16進数の場合は4桁で区切ります。
1001と0110となります。
それぞれを16進数にすると、1001=9、0110=6です。
0b1001.011を16進数表記にすると9.6となります。
(2)
0b110.1011
8進数の場合
110 = 6
101 = 5
100 = 4
なので、0b110.1011は0o6.54とかけます。
16進数の場合
0110 = 6
1011 = B
なので、0b110.1011 は0x6.Bとかけます。
(1)
0o32.65
3 = 0b011
2 = 0b010
6 = 0b110
5 = 0b101
なので、0o32.65は0b011010.110101となります。
(2)
0x4A.C9
4 = 0b0100
A = 0b1010
C = 0b1100
9 = 0b1001
なので、0x4A.C9は0b01001010.11001001となります。