n進数と基数変換
10進数
0から9までの数字を使い、1から9まで数えたら位を1つ上げて(桁を1つ増やして)10にする数え方が一般に行われている。こうした数え方は10進法と呼ばれ、それらの数は10進数と呼ばれている。この数え方は、人が自分の手の指を使って物を数えるのに適していたため、そこから生まれたと考えらている。
0, 1, 2, 3, 4, 5, 6, 7, 8, 9まで数えたらその次が10となり、11, 12, ..., 19まで数えたらその次が20となり、99まで数えたらその次が100となり、999まで数えたらその次が1000となる。桁をこのように増やしてゆくことで限られた数字で無限の数を表現することができる。このような記数法は10進の位取り記数法と呼ばれている。
漢字で二千四百六十八という数は、一の位が8つで、十の位が6つで、百の位が4つで、千の位が2つであることを意味している。アラビア数字による位取り記数法では2468のように記され、漢字では記されていた千、百、十という各位を表す文字が記されない。しかし、例えば2468は\( 2 + 4 + 6 + 8 \)であることを意味しているわけではなく\( 2000 + 400 + 60 + 8 \)であることを意味している。
\( \neq \)は等しくないという意味である。この二つ目の数式にある\( 10^3 = 1000,\ 10^2 = 100,\ 10^1 = 10,\ 10^0 = 1 \)が各桁の数字が属している位であり、それらはそれぞれ千の位、百の位、十の位、一の位または桁と呼ばれている。各位が持っている千、百、十、一という値を数学では桁値と呼ぶが、計算機科学の世界では重みと呼ばれている。桁のそれぞれの数字はその桁値だけ倍にした数を表している。
2進数
電子計算機やコンピュータの内部では、電圧の高低差を利用した2進法による計算が行わている。2進法は0と1という2つの数字だけを使って表されている。2進法では、0, 1, 10, 11, 100, 101, 110, 111, 1000, ...のように桁が増えてゆく。これは2進の位取り記数法である。
2進法では、10は「ジュー」と読むのではなく「イチゼロ」と読む。同様に11は「ジューイチ」ではなく「イチイチ」、100は「ヒャク」ではなく「イチゼロゼロ」、111は「イチイチイチ」と電話番号のように読む。
例えば、2進数の1101「イチイチゼロイチ」を多項式にして表せば、次のような数であることを意味している。
ただし、2進法での桁値である例えば1000, 100, 10は、漢字でいうところの千、百、十を意味するのではない。2進数での1000は「イチゼロゼロゼロ」、100は「イチゼロゼロ」、10は「イチゼロ」という桁値を持っていることになる。
2進数の1桁は、計算機科学、情報数学、情報工学の分野ではビットという単位で呼ばれている。C言語などのプログラミング言語では1011BのようにBを添えて2進数であることを示す。Bは2進数を表す英語binary numberの頭文字bによる。
2進数を10進数への変換
桁値を理解することが10進数へと他の進数を変換するために役立つ。次の数式は2進数である1101をそれに対応する10進数へと変換している多項式である。ここでは\( = \)の代わりに\( \rightarrow \)という記号を使って2進数と10進数との間の対応関係を表している。下の式の計算結果から2進数の1101が10進数では13に対応していることが分かる。
上の数式では、\( \rightarrow \)の左辺が2進数であり、\( \rightarrow \)の右辺が10進数である。2進数であることを\( (...)_2 \)と表し、10進数であることを\( (...)_{10} \)と表している。2進数である1101は10進数では13に対応している。2進数のそれぞれの位の重み、すなわち桁値を10進数で表すと、\( 2^3 = 8,\ 2^2 = 4,\ 2^1 = 2,\ 2^0 = 1\)になることが分かる。2進数でのそれぞれの桁が10進数ではこのような重みを持っていることを理解していれば、2進数から10進数への変換は簡単な算術でたやすく行える。
2進数と10進数の対応表
次の表は2進数と10進数の対応関係を示している。この表から2進数の1101が10進数の13に対応することが見て取れる。
2進数 | 10進数 |
---|---|
0 | 0 |
1 | 1 |
10 | 2 |
11 | 3 |
100 | 4 |
101 | 5 |
110 | 6 |
111 | 7 |
1000 | 8 |
1001 | 9 |
1010 | 10 |
1011 | 11 |
1100 | 12 |
1101 | 13 |
1110 | 14 |
1111 | 15 |
10000 | 16 |
10001 | 17 |
10010 | 18 |
10011 | 19 |
10100 | 20 |
10101 | 21 |
10110 | 22 |
10111 | 23 |
11000 | 24 |
11001 | 25 |
11010 | 26 |
11011 | 27 |
11100 | 28 |
11101 | 29 |
11110 | 30 |
11111 | 31 |
100000 | 32 |
100001 | 33 |
100010 | 34 |
100011 | 35 |
100100 | 36 |
100101 | 37 |
100110 | 38 |
100111 | 39 |
101000 | 40 |
101001 | 41 |
101010 | 42 |
101011 | 43 |
101100 | 44 |
101101 | 45 |
101110 | 46 |
101111 | 47 |
110000 | 48 |
110001 | 49 |
110010 | 50 |
110011 | 51 |
110100 | 52 |
110101 | 53 |
110110 | 54 |
110111 | 55 |
111000 | 56 |
111001 | 57 |
111010 | 58 |
111011 | 59 |
111100 | 60 |
111101 | 61 |
111110 | 62 |
111111 | 63 |
1000000 | 64 |
1000001 | 65 |
1000010 | 66 |
1000011 | 67 |
1000100 | 68 |
1000101 | 69 |
1000110 | 70 |
1000111 | 71 |
1001000 | 72 |
1001001 | 73 |
1001010 | 74 |
1001011 | 75 |
1001100 | 76 |
1001101 | 77 |
1001110 | 78 |
1001111 | 79 |
1010000 | 80 |
1010001 | 81 |
1010010 | 82 |
1010011 | 83 |
1010100 | 84 |
1010101 | 85 |
1010110 | 86 |
1010111 | 87 |
1011000 | 88 |
1011001 | 89 |
1011010 | 90 |
1011011 | 91 |
1011100 | 92 |
1011101 | 93 |
1011110 | 94 |
1011111 | 95 |
1100000 | 96 |
1100001 | 97 |
1100010 | 98 |
1100011 | 99 |
1100100 | 100 |
1100101 | 101 |
1100110 | 102 |
1100111 | 103 |
1101000 | 104 |
1101001 | 105 |
1101010 | 106 |
1101011 | 107 |
1101100 | 108 |
1101101 | 109 |
1101110 | 110 |
1101111 | 111 |
1110000 | 112 |
1110001 | 113 |
1110010 | 114 |
1110011 | 115 |
1110100 | 116 |
1110101 | 117 |
1110110 | 118 |
1110111 | 119 |
1111000 | 120 |
1111001 | 121 |
1111010 | 122 |
1111011 | 123 |
1111100 | 124 |
1111101 | 125 |
1111110 | 126 |
1111111 | 127 |
10000000 | 128 |
上の表においてもう一つ注目すべき点は、この表から2進数の桁値を10進数で表したときの値が見て取れることである。2進数の1が10進数では1、2進数の10が10進数では2、2進数の100が10進数では4、2進数の1000が10進数では8になっている。2進数で桁が増えているところでの10進数の値を見れば、2進数のそれぞれの位を10進数で表した場合の桁値が判断できる。その対応関係は次の表の通りになる。
2進数 | 10進数 | 10進冪乗 |
---|---|---|
1 | 1 | \( 2^0 \) |
10 | 2 | \( 2^1 \) |
100 | 4 | \( 2^2 \) |
1000 | 8 | \( 2^3 \) |
10000 | 16 | \( 2^4 \) |
100000 | 32 | \( 2^5 \) |
1000000 | 64 | \( 2^6 \) |
10000000 | 128 | \( 2^7 \) |
2進数で位が増えたところの10進数での値を見ると、2進数の各位の重み(桁値)を10進数で表した値が直前の数の2倍ずつ増えていることが、この表から見て取れる。これは初項が1、公比が2の等比数列である。初項は最初の数、公比の2はこの数列が常に2倍ずつ増えていることによる。
冪乗で表したとき、全ての桁値に共通する2の数字は基底または単に底と呼ばれている。計算機科学ではこれを基数と呼ぶことが多いが、数学でいう集合数のことではない。英語ではbaseまたはradix。2進数の2はここから来ている。10進数は10を基底とする進法である。さらに、等比数列の特徴として、基数の右上の指数が0から順に0, 1, 2, 3, 4, 5, ...と増えていることがこの表から見て取れる。
ちなみに、\( a = b^i \)と表されるとき、指数の形で表されているこのiの値はbを基底とするaの値の対数とも呼ばれている。例えば\( 2^7 \)の指数7は2を基底とする128の対数と呼び、\( 2^5 \)の指数5は2を基底とする32の対数と呼ぶ。それぞれ次のように書く。
冪乗に関するちょっとした注意
ただし、\( r \)の0乗と\( r \)の1乗はそれぞれ次のようになることに注意が必要である。
なぜなら、冪乗は厳密には次のような演算を意味するからである。
8進数や12進数を10進数へと変換
例えば8進法や12進数でも同様のことが成り立つ。8進法は0から7までの数字で表す位取り記数法であり、12進法は0から9、そしてTとEまでの英数字で表す位取り記数法である。TはtenのTで10進数で10に対応し、EはelevenのEで10進数で11に対応する。
2進数の場合と同様の方法で8進数や12進数を10進数へと変換することができる。ここでは\( (...)_r \)という形でr進数であることを示す。rはradixのrで、rには任意の自然数が入る。ここでは例として8進数と12進数を表すので、それぞれのrに8と12が入っている。
これらの計算のとおり、、8進数の2308を10進数に変換すると10進数の1224になり、12進数の3TEを10進数に変換すると10進数の563になることが分かる。
8進数と12進数の桁値は次のような対応表になる。
8進数 | 10進数 | 10進冪乗 | 10進対数 |
---|---|---|---|
1 | 1 | \( 8^0 \) | 0 |
10 | 8 | \( 8^1 \) | 1 |
100 | 64 | \( 8^2 \) | 2 |
1000 | 512 | \( 8^3 \) | 3 |
10000 | 4096 | \( 8^4 \) | 4 |
100000 | 32768 | \( 8^5 \) | 5 |
1000000 | 262144 | \( 8^6 \) | 6 |
10000000 | 2097152 | \( 8^7 \) | 7 |
100000000 | 16777216 | \( 8^8 \) | 8 |
12進数 | 10進数 | 10進冪乗 | 10進対数 |
---|---|---|---|
1 | 1 | \( 12^0 \) | 0 |
10 | 12 | \( 12^1 \) | 1 |
100 | 144 | \( 12^2 \) | 2 |
1000 | 1728 | \( 12^3 \) | 3 |
10000 | 20736 | \( 12^4 \) | 4 |
100000 | 248832 | \( 12^5 \) | 5 |
1000000 | 2985984 | \( 12^6 \) | 6 |
10000000 | 35831808 | \( 12^7 \) | 7 |
100000000 | 429981696 | \( 12^8 \) | 8 |
小数の場合
小数ではどうか。例えば10進数の小数0.123は次のような多項式に表すことができる。マイナスの指数を持つ冪乗は小数を表している。
10進数の整数+小数の数75.29を多項式に表すと次のようになる。
したがって、2進数の小数0.101を10進数に変換するには次のように計算すればよい。2進数の各桁値を10進数の冪乗で表したとき、基底の数(基数)は10ではなく2になる。この計算結果から、2進数の0.101は10進数では0.625だと分かる。
2進数の小数の各桁値を表にしてみるとこうなる。
2進数 | 10進数 | 10進冪乗 | 10進分数 | 10進対数 |
---|---|---|---|---|
0.1 | 0.5 | \( 2^{-1} = 0.5^1 \) | \( \dfrac{1}{2^1} \) | -1 |
0.01 | 0.25 | \( 2^{-2} = 0.5^2 \) | \( \dfrac{1}{2^2} \) | -2 |
0.001 | 0.125 | \( 2^{-3} = 0.5^3 \) | \( \dfrac{1}{2^3} \) | -3 |
0.0001 | 0.0625 | \( 2^{-4} = 0.5^4 \) | \( \dfrac{1}{2^4} \) | -4 |
0.00001 | 0.03125 | \( 2^{-5} = 0.5^5 \) | \( \dfrac{1}{2^5} \) | -5 |
0.000001 | 0.015625 | \( 2^{-6} = 0.5^6 \) | \( \dfrac{1}{2^6} \) | -6 |
0.0000001 | 0.0078125 | \( 2^{-7} = 0.5^7 \) | \( \dfrac{1}{2^7} \) | -7 |
0.00000001 | 0.00390625 | \( 2^{-8} = 0.5^8 \) | \( \dfrac{1}{2^8} \) | -8 |
マイナスの指数を持つ冪乗
\( r \)のマイナス\( i \)乗は次のような意味を表している。\( = \)は左右が互いに等しいことを示す。\( r \)は基底を意味する英語radix――base of numberとも言う――のr、\( i \)は指数を意味する英語indexのi。
\( i \)に具体的な数を代入して表すとこうなる。
指数部がマイナスになっている冪乗は、1以下0以上の数、すなわち小数を表している。
r進数から10進数への変換
r進数からその数に対応する10進数への数の変換は、一般に次のようにして計算することができる。見やすくするために各位の計算を表している各項を括弧でくくった。
\( I_n \)のIは整数を表す英語integerの頭文字、添え字のnは桁数を表す。\( r \)とは基底を表す英語radixの頭文字であり、2進数の場合は2、5進数の場合は5が入る。その添え字のnは与えられた数の桁数を表している。\( \sum \)はサメーション、つまり合計のことであり、ギリシア文字でシグマと読む。\( a \)は与えられた数の各位にある数字、\( n \)は与えられた数の桁の数のことで、0から数えるので\( n \)から1を引いてある。\( k \)は桁値を冪乗で表したときの指数を表し、低い位から何桁目かを指している。サメーションの下の\( k=0 \)は0から始まることを表し、サメーションの上の\( n \)(任意の自然数)はその数の桁数回足し算が続くことを意味している。足し算なので交換法則、すなわち足す順番が自由でよいという法則が成り立ち、計算の順番を逆にしても同じ値が得られる。
小数の場合は次のようになる。
整数部と小数部を両方持つ数の場合はこう一般化できる。
数学の文字式では普通、掛け算の演算記号\( \times \)または\( \cdot \)を省略するので次のように書ける。
整数部と小数部を両方持つ数の場合は次のとおり。
数学記号と数式で表現するとなんだか難しく見えてしまうけれども、その変換規則は各桁を表す定数(係数)にr進数の基数の冪乗を掛けてそれらの値の合計を求める式だから簡単。
ちなみに、この文字式は多項式のように見えるが、小数部の変数rの指数に正数でなく負数が使われているために通常の多項式の条件を満たさない。したがって通常の多項式とは区別されてローラン多項式と呼ばれている。
したがって位取り記数法によって表された数値は、整数部は多項式として展開できるが、小数部はローラン多項式として展開できる。
あるr進数から別のr進数への変換は基数変換と呼ばれている。
16進数
計算機科学の中では、2進数を人がより扱いやすくするために16進数を用いて表すことが多い。16進数の表記にはアラビア数字の0〜9とローマ字の大文字A〜Fか小文字a〜fが使われている。
2進数 | 4進数 | 8進数 | 16進数 | 10進数 |
---|---|---|---|---|
0 | 0 | 0 | 0 | 0 |
1 | 1 | 1 | 1 | 1 |
10 | 2 | 2 | 2 | 2 |
11 | 3 | 3 | 3 | 3 |
100 | 10 | 4 | 4 | 4 |
101 | 11 | 5 | 5 | 5 |
110 | 12 | 6 | 6 | 6 |
111 | 13 | 7 | 7 | 7 |
1000 | 20 | 10 | 8 | 8 |
1001 | 21 | 11 | 9 | 9 |
1010 | 22 | 12 | A | 10 |
1011 | 23 | 13 | B | 11 |
1100 | 30 | 14 | C | 12 |
1101 | 31 | 15 | D | 13 |
1110 | 32 | 16 | E | 14 |
1111 | 33 | 17 | F | 15 |
10000 | 40 | 20 | 10 | 16 |
10001 | 41 | 21 | 11 | 17 |
10010 | 42 | 22 | 12 | 18 |
10011 | 43 | 23 | 13 | 19 |
10100 | 50 | 24 | 14 | 20 |
10101 | 51 | 25 | 15 | 21 |
10110 | 52 | 26 | 16 | 22 |
10111 | 53 | 27 | 17 | 23 |
11000 | 60 | 30 | 18 | 24 |
11001 | 61 | 31 | 19 | 25 |
11010 | 62 | 32 | 1A | 26 |
11011 | 63 | 33 | 1B | 27 |
11100 | 70 | 34 | 1C | 28 |
11101 | 71 | 35 | 1D | 29 |
11110 | 72 | 36 | 1E | 30 |
11111 | 73 | 37 | 1F | 31 |
100000 | 80 | 40 | 20 | 32 |
16進数を10進数へ基数変換
例えば16進数の数8C1を10進数へと基数変換してみる。16進数なので基底16、8C1なので3桁。これらを先程の公式\( \sum_{i=0}^{n-1} x_i r^{i} \)の変数\( r \)と\( n \)にそれぞれ代入すると、\( r = 16 \)、\( n = 3 \)となる。16進数のCは10進数では12に当たるので12として計算する。したがって次のように計算することができる。この計算結果から、16進数の8C1が10進数では2257に対応することが分かる。
小数点を持つ16進数の2F.5Aを10進数に基数変換するには、次のように計算することができる。16進数のFは10進数では15、16進数のAは10進数では10なので、その数に置き換えて計算する。
16進数 | 10進数 | 10進冪乗 | 10進対数 |
---|---|---|---|
0.0001 | 0.00001525879 | \( 16^{-4} \) | -4 |
0.001 | 0.0002441406 | \( 16^{-3} \) | -3 |
0.01 | 0.00390625 | \( 16^{-2} \) | -2 |
0.1 | 0.0625 | \( 16^{-1} \) | -1 |
1 | 1 | \( 16^0 \) | 0 |
10 | 16 | \( 16^1 \) | 1 |
100 | 256 | \( 16^2 \) | 2 |
1000 | 4096 | \( 16^3 \) | 3 |
10000 | 65536 | \( 16^4 \) | 4 |
100000 | 1048576 | \( 16^5 \) | 5 |
1000000 | 16777216 | \( 16^6 \) | 6 |
10000000 | 268435456 | \( 16^7 \) | 7 |
100000000 | 4294967296 | \( 16^8 \) | 8 |
10進数から16進数への基数変換
上の二つの計算が正しかったかどうか検算するために10進数から16進数への基数変換をしてみる。
10進数からr進数への基数変換には剰余演算を用いることができる。剰余演算は計算機科学ではモジュロ演算とも呼ばれている。
10進数の数を変換したい16進数の基数(基底)である16で割っていき、答が0になるまで繰り返せば、それらの余りが対応する16進数の各桁の値になる。この計算から10進数の2241は16進数の8C1に対応することが分かる。この計算法は連続除法や剰余法と呼ばれることがある。
上の式ではちょっとわかりにくいので計算の手続きを筆算風の表にしてみた。最初の余りが16進数の1の位に、2番目の余りが16進数の10の位に、3番目の余りが16進数の100の位に、それぞれ対応している。
次に、10進数の47.3515625を16進数に基数変換する。この場合、整数部と小数部を分けて考え、それぞれ別の方法で求める。整数部は16進数の基底である16で割る計算を繰り返し、それぞれの余りの値が16進数に変換したときの各桁の値になる。
小数部は逆に16を掛ける計算をする。その答えから整数部を取り除いた値にさらに16を掛ける。そしてその計算を繰り返す。答えの値から小数部がなくなれば計算を終了。それらの答えの整数部の値が16進数に変換したときの各桁の値になる。桁の並べ方が整数部とは逆順(上から下へ)になるので要注意。
まずは整数部から。10進数の15は16進数ではF。整数部は16進数で2Fと求まる。
筆算風の表にして表すと次のように計算できる。
そして小数部。10進数の10は16進数ではA。小数部は16進数でA5と求まる。
筆算風の表で表すと次のようになる。
整数部の計算結果と小数部の計算結果を足し合わせると、16進数の2F.A5が求まることが分かる。
10進数から2進数への基数変換
10進数から2進数への基数変換も、整数部、小数部ともに同様の方法で計算することができる。例えば、10進数の87.53を2進数に基数変換するには、次のように計算する。整数部と小数部でそれぞれ別々の計算方法を用いる。
10進数の整数部を変換したい2進数の基底数である2で割り、その答えを更に2で割る。この計算を答えが0になるまで繰り返す。このときの余りの値は0か1のいずれかになる。それらの余りの値を小さい桁から順番に並べれば2進数へと変換した整数部の値になる。
10進数の小数部には変換したい2進数の基底数である2を掛け、その答えの小数部だけを取り出し、その小数に更に2を掛ける。この計算を答えが整数部だけになるまで繰り返す。掛け算の各計算の答えの整数部は0か1のいずれかになる。この整数部を大きい桁から順番に並べていけば2進数へと変換された小数部になる。最後に整数部と小数部を足しあわせれば計算が完了する。
筆算風に表すと次のように書ける。
次は小数部の計算。
筆算表を使うと次のようになる。
この場合、小数部は計算を繰り返しても繰り返しても答えの小数部が0にならず、おそらくは無限に続く小数になってしまう。そうした場合は途中で中断するよりほかない。
最後に整数部と小数部を足し合わせる。
10進数からr進数への基数変換のアルゴリズム
整数部については一般に次のように求めることができる。xが変換元である10進数の任意の整数、rが変換先の数の基数、yが商、aが余り。
代数的な表し方をすると次のようになる。
小数部については次のように計算することができる。ここで\( a.b \)のaは小数の整数部、bは小数部を表す。
スクリプティング言語の関数やメソッドを利用した基数変換
Python 3では、2進数・8進数・16進数から10進数へ基数変換するためにint()関数を利用することができる。int()関数の第1引数に、変換したい数値を一重引用符か二重引用符で挟んで指定し、第2引数にその基数の値を指定する。
$ python3 >>> int("1111",2) 15 >>> int("16",8) 14 >>> int("1E",16) 30 >>> exit
変換前の数値にプレフィックス(接頭辞)が付けられていても大丈夫。
>>> int("0b10101",2) 21 >>> int("0o37",8) 31 >>> int("0x9",16) 9 >>> exit
10進数から2進数へ、10進数から8進数へ、10進数から16進数へ基数変換したいときにはそれぞれに専用の関数が用意されている。2進数へ変換する場合にはbin()関数、8進数へ変換する場合にはoct()関数、16進数へ変換する場合にはhex()関数を利用する。
>>> bin(125) '0b1111101' >>> bin(125)[2:] '1111101' >>> oct(56) '0o70' >>> oct(56)[2:] '70' >>> hex(64) '0x40' >>> hex(64)[2:] '40' >>> exit
これらの関数の出力値にはプレフィックス(接頭辞)が付いてくるが、[2:]によってそれを除去することができる。
Python 3では、format()関数やstr.format()メソッドにも10進数を2進数ないしは8進数ないしは16進数に基数変換する能力がある。format()関数とstr.format()メソッドでは次の書式指定子を利用する。
- 2進数はb、
- 8進数はo、
- 16進数の小文字はx、16進数の大文字はX。
次の例では10進数の30を2進数・8進数・16進数にそれぞれ基数変換している。
$ python3 Python 3.13.5 >>> format(30,'b') '11110' >>> "{:b}".format(30) '11110' >>> format(30,'o') '36' >>> "{:o}".format(30) '36' >>> format(30,'x') '1e' >>> "{:x}".format(30) '1e' >>> format(30,'X') '1E' >>> "{:X}".format(30) '1E' >>> exit
Python 3ではそのうえさらにf-stringsという文字列リテラルを利用する方法がある。次の例では10進数の31を2進数・8進数・16進数にそれぞれ基数変換している。
$ python3 Python 3.13.5 >>> f"{31:b}" '11111' >>> f"{31:o}" '37' >>> f"{31:x}" '1f' >>> f"{31:X}" '1F' >>> exit
R言語では2進数・8進数・16進数から10進数への基数変換にstrtoi()関数を利用できる。第1引数には引用符付きで数字を指定し、第2引数にはbase=の後にその数字の基数を指定する。2進数ならば2が基数、8進数ならば8が基数、16進数ならば16が基数。
$ R R version 4.5.0 > strtoi("11111",base=2) [1] 31 > strtoi("37",base=8) [1] 31 > strtoi("1F",base=16) [1] 31 > q() Save workspace image? [y/n/c]: n
R言語で10進数から2進数へ基数変換するにはintToBits()関数を利用できる。ただしこの関数はスペースで区切られた2桁の2進法表現をraw型で返す。しかも桁は逆順に並んでいる。そのため、この関数によって返されたデータを整形する処理も一緒に必要になる。
次に10進数の35を2進数に基数変換する処理の例を示す。
$ R R version 4.5.0 > bin1 = intToBits(35L) > bin1 [1] 01 01 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 [26] 00 00 00 00 00 00 00 > typeof(bin1) [1] "raw" > bin2 = as.integer(bin1) > bin2 [1] 1 1 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > bin3 = rev(bin2) > bin3 [1] 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 1 > bin4 = paste(bin3,collapse="") > bin4 [1] "00000000000000000000000000100011" > bin5 = sub("^0+","",bin4) > bin5 [1] "100011" > q() Save workspace image? [y/n/c]: n
数値リテラルの35Lは35がInteger型の数値であることを表している。それをintToBits()関数に入力して出力された値を変数bin1に代入。しかし出力された値をtypeof()関数で調べてみるとraw型になってしまっている。as.integer()関数によってそれを再びInteger型に戻して変数bin2に代入。次にrev()関数で桁順を反転させて変数bin3に代入。次にpaste()関数によって数字間の空白を取り除いて変数bin4に代入。次にsub()関数によって余分な0を取り除いて最終的な結果を変数bin5に代入している。ただしrev()関数はpaste()関数より前で使う必要があることに要注意。
ちなみに、R言語の代入演算子は<-
のはずだと思われたかもしれが、左辺への代入ならば=
が使える。
R言語で10進数から16進数へ基数変換するにはas.hexmode()関数が便利。
$ R R version 4.5.0 > as.hexmode(35L) [1] "23" > q() Save workspace image? [y/n/c]: n
R言語で10進数を8進数へと基数変換する便利な方法はどうもないらしい。上述したアルゴリズムをコード化してちょっとしたスクリプトを組むしかないと思う。
GNU Octaveではbase2dec()関数とdec2base()関数を利用できる。base2dec()関数はr進数から10進数への基数変換をしてくれ、dec2base()関数は10進数からr進数への基数変換をしてくれる。
base2dec()関数では第1引数に変換したい数値を引用符で挟んで指定し、第2引数には第1引数で指定した数値の基数(何進数か)を指定する。dec2base()関数では第1引数に変換したい10進数の数値を指定し、第2引数に変換後の数値の基数(何進数へ変換したいか)を指定する。引数の指定方法が異なることに要注意。
$ octave GNU Octave, version 9.4.0 octave:1> base2dec("11011",2) ans = 27 octave:2> dec2base(27,2) ans = 11011 octave:3> base2dec("33",8) ans = 27 octave:4> dec2base(27,8) ans = 33 octave:5> base2dec("1b",16) ans = 27 octave:6> dec2base(27,16) ans = 1B octave:7> exit
Juliaではstring()関数とparse()関数を利用できる。string()関数は10進数からr進数へ基数変換してくれ、parse()関数はr進数から10進数へ基数変換してくれる。
string()関数の第1引数には10進数を指定して第2引数にはbase=で変換先の基数を指定する。parse()関数の第1引数にはデータ型名を指定し、第2引数に文字列リテラルとして変換前の数値を指定し、第3引数では第2引数で指定した数値の基数を指定する。
$ julia Version 1.11.6 julia> string(8,base=2) "1000" julia> parse(Int,"1000",base=2) 8 julia> string(12,base=8) "14" julia> parse(Int,"14",base=8) 12 julia> string(13,base=16) "d" julia> parse(Int,"d",base=16) 13 julia> exit()
Rubyでは基数変換のために整数オブジェクトの.to_s()メソッドと文字列オブジェクトの.to_i()メソッドを利用することができる。.to_s()メソッドは10進数をr進数へ基数変換するために利用でき、.to_i()メソッドはr進数を10進数に基数変換するために利用できる。
整数オブジェクトの.to_s()メソッドでは()に変換先の基数を指定するが、文字列オブジェクトの.to_i()メソッドでは()に変換元の基数を指定するという違いがある。
ここではRubyのREPL(レプル)であるIRBを利用した。
$ ruby -v ruby 3.3.8 $ irb -v irb 1.13.1 $ irb irb(main):001> 52.to_s(2) => "110100" irb(main):002> "110100".to_i(2) => 52 irb(main):003> 37.to_s(8) => "45" irb(main):004> "45".to_i(8) => 37 irb(main):005> 29.to_s(16) => "1d" irb(main):006> "1D".to_i(16) => 29 irb(main):007> exit
Javaで基数変換をするにはIntegerクラスやLongクラスの.toString()メソッドと.parseInt()メソッドを利用することができる。.toString()メソッドは10進数からr進数への基数変換に利用でき、.parseInt()メソッドはr進数から10進数への基数変換に利用できる。
.toString()メソッドでは第1引数にint型の10進数を指定し、第2引数に変換先の基数を指定する。.parseInt()メソッドでは第1引数にn進数をstring型で指定し、第2引数にその基数を指定する。
JavaにはJShellというREPL(レプル)があるのでここではそれを利用した。
$ jshell | JShellへようこそ -- バージョン21.0.8 | 概要については、次を入力してください: /help intro jshell> Integer.toString(25,2); $1 ==> "11001" jshell> Integer.parseInt("11001",2); $2 ==> 25 jshell> Integer.toString(25,8); $3 ==> "31" jshell> Integer.parseInt("31",8); $4 ==> 25 jshell> Integer.toString(28,16); $5 ==> "1c" jshell> Integer.parseInt("1c",16); $6 ==> 28 jshell> /exit | 終了します
ScalaでもJavaとまったく同じやり方でIntegerクラスやLongクラスの.toString()メソッドとparseInt()メソッドを使って基数変換を行うことができる。
$ scala Welcome to Scala 2.11.12 (OpenJDK 64-Bit Server VM, Java 21.0.8). Type in expressions for evaluation. Or try :help. scala> Integer.toString(31,2) res0: String = 11111 scala> Integer.parseInt("11111",2) res1: Int = 31 scala> Integer.toString(31,8) res2: String = 37 scala> Integer.parseInt("37",8) res3: Int = 31 scala> Integer.toString(31,16) res4: String = 1f scala> Integer.parseInt("1f",16) res5: Int = 31 scala> sys.exit
また、BigIntクラスを利用して大きい数値を扱うこともできる。
scala> var bigHex = BigInt("ffffff",16) bigHex: scala.math.BigInt = 16777215 scala> bigHex.toString(2) res9: String = 111111111111111111111111 scala> bigHex.toString(8) res10: String = 77777777 scala> bigHex.toString(10) res11: String = 16777215 scala> sys.exit
残念ながらここで挙げたいくつかのスクリプティング言語の関数やメソッドはすべて整数部の基数変換にしか対応していない。小数部はアルゴリズムが異なるため、それ向けのスクリプトを書く必要がある。
まとめ
r進数
- 10進数(decimal numbers)
- 10を基底とする位取り記数法。0, 1, 2, 3, 4, 5, 6, ..., 9, 10, 11 , 12, ...19, 20, 21, ..., 99, 100, 101, ...のように位を上げてゆく数え方。
- 2進数(binary numbers)
- 2を基底とする位取り記数法。0と1の数字だけを用いて、0, 1, 10, 11, 100, 101, 110, 111, 1000, ...のように位を上げてゆく数え方。
- 16進数(hexadecimal numbers)
- 16を基底とする位取り記数法。0〜9の次はA, B, C, D, E, F 10, 11, 12, ..., 19, 1A, 1B,..., 1F, 20, 21, ...のように位を上げてゆく数え方。
- 位取り記数法
- 数に位という概念を導入し、1つ下の位で数字がひと通り数えられるごとに1つ上の位に1つずつ繰り上がってゆく数え方およびその記数法。位は桁とも呼ぶ。
- 桁値(重み)
- 位取り記数法において各桁(各位)はそれぞれ異なる数の単位を表している。その単位は桁値または重みと呼ばれている。それぞれの桁の数字はその桁値だけ倍にした数であることを意味している。例えば10進法では、10の位は10倍を意味し、100の位は100倍を意味している。2進法では、10(イチゼロ)の位は10進法での2倍に相当し、100(イチゼロゼロ)の位は10進法での4倍に相当している。
r進数から10進数への基数変換のアルゴリズム
-
与えられた数値を整数部と小数部とに分ける。
16進数を10進数へ基数変換する例を挙げてみた。
\[ (E941.0F5)_{16} = (E941)_{16} + (0.0F5)_{16} \] -
整数部の各桁を10進数における「各桁の値×桁値」に基数変換し、それらすべての桁を表す項を足し合わせた総和の式にする。
\[ (E941)_{16} \rightarrow (14 \times 16^3 + 9 \times 16^2 + 4 \times 16^1 + 1 \times 16^0)_{10} \]Eは10進数では14に当たる。整数部では1の位の桁値の指数が0から始まることに要注意。
-
小数部の各桁を10進数における「各桁の値×桁値」に基数変換し、それらすべての桁を表す項を足し合わせた総和の式にする。
\[ (0.0F5)_{16} \rightarrow (0 \times \dfrac{1}{16} + 15 \times \dfrac{1}{16^2} + 5 \times \dfrac{1}{16^3})_{10} \]Fは10進数では15に当たる。
-
整数部を計算する。
\begin{align*} & (14 \times 16^3 + 9 \times 16^2 + 4 \times 16^1 + 1 \times 16^0)_{10} \\ & = (14 \times 4096 + 9 \times 256 + 4 \times 16 + 1 \times 1)_{10} \\ & = (57344 + 2304 + 64 + 1)_{10} \\ & = (59713)_{10} \end{align*} -
小数部を計算する。
\begin{align*} & (0 \times \dfrac{1}{16} + 15 \times \dfrac{1}{16^2} + 5 \times \dfrac{1}{16^3})_{10} \\ & = (0 \times 0.0625 + 15 \times 0.00390625 + 5 \times 0.000244140625)_{10} \\ & = (0 + 0.05859375 + 0.001220703125)_{10} \\ & = (0.059814453125)_{10} \end{align*} -
整数部の計算結果と小数部の計算結果を足し合わせる。
\[ (59713 + 0.059814453125)_{10} = (59713.059814453125)_{10} \]
10進数・2進数・8進数・16進数の桁値(各々の位の重み)
10進数の桁 | 桁値 |
---|---|
0.0000000001 | \( \dfrac{1}{10^{10}} \) |
0.000000001 | \( \dfrac{1}{10^9} \) |
0.00000001 | \( \dfrac{1}{10^8} \) |
0.0000001 | \( \dfrac{1}{10^7} \) |
0.000001 | \( \dfrac{1}{10^6} \) |
0.00001 | \( \dfrac{1}{10^5} \) |
0.0001 | \( \dfrac{1}{10^4} \) |
0.001 | \( \dfrac{1}{10^3} \) |
0.01 | \( \dfrac{1}{10^2} \) |
0.1 | \( \dfrac{1}{10^1} \) |
1 | \( 10^0 \) |
10 | \( 10^1 \) |
100 | \( 10^2 \) |
1000 | \( 10^3 \) |
10000 | \( 10^4 \) |
100000 | \( 10^5 \) |
1000000 | \( 10^6 \) |
10000000 | \( 10^7 \) |
100000000 | \( 10^8 \) |
1000000000 | \( 10^9 \) |
10000000000 | \( 10^{10} \) |
2進数の桁 | 対応する10進数 | 桁値 |
---|---|---|
0.00000000001 | 0.0009765625 | \( \dfrac{1}{2^{10}} \) |
0.0000000001 | 0.001953125 | \( \dfrac{1}{2^9} \) |
0.000000001 | 0.00390625 | \( \dfrac{1}{2^8} \) |
0.00000001 | 0.0078125 | \( \dfrac{1}{2^7} \) |
0.0000001 | 0.015625 | \( \dfrac{1}{2^6} \) |
0.000001 | 0.03125 | \( \dfrac{1}{2^5} \) |
0.00001 | 0.0625 | \( \dfrac{1}{2^4} \) |
0.0001 | 0.125 | \( \dfrac{1}{2^3} \) |
0.01 | 0.25 | \( \dfrac{1}{2^2} \) |
0.1 | 0.5 | \( \dfrac{1}{2^1} \) |
1 | 1 | \( 2^0 \) |
10 | 2 | \( 2^1 \) |
100 | 4 | \( 2^2 \) |
1000 | 8 | \( 2^3 \) |
10000 | 16 | \( 2^4 \) |
100000 | 32 | \( 2^5 \) |
1000000 | 64 | \( 2^6 \) |
10000000 | 128 | \( 2^7 \) |
100000000 | 256 | \( 2^8 \) |
1000000000 | 512 | \( 2^9 \) |
10000000000 | 1024 | \( 2^{10} \) |
8進数の桁 | 対応する10進数 | 桁値 |
---|---|---|
0.0000000001 | 0.0000000009313226 | \( \dfrac{1}{8^{10}} \) |
0.000000001 | 0.000000007450581 | \( \dfrac{1}{8^9} \) |
0.00000001 | 0.00000005960464 | \( \dfrac{1}{8^8} \) |
0.0000001 | 0.0000004768372 | \( \dfrac{1}{8^7} \) |
0.000001 | 0.000003814697 | \( \dfrac{1}{8^6} \) |
0.00001 | 0.00003051758 | \( \dfrac{1}{8^5} \) |
0.0001 | 0.0002441406 | \( \dfrac{1}{8^4} \) |
0.001 | 0.001953125 | \( \dfrac{1}{8^3} \) |
0.01 | 0.015625 | \( \dfrac{1}{8^2} \) |
0.1 | 0.125 | \( \dfrac{1}{8^1} \) |
1 | 1 | \( 8^0 \) |
10 | 8 | \( 8^1 \) |
100 | 64 | \( 8^2 \) |
1000 | 512 | \( 8^3 \) |
10000 | 4096 | \( 8^4 \) |
100000 | 32768 | \( 8^5 \) |
1000000 | 262144 | \( 8^6 \) |
10000000 | 2097152 | \( 8^7 \) |
100000000 | 16777216 | \( 8^8 \) |
1000000000 | 134217728 | \( 8^9 \) |
10000000000 | 1073741824 | \( 8^{10} \) |
16進数の桁 | 対応する10進数 | 桁値 |
---|---|---|
0.0000000001 | 0.0000000000009094947 | \( \dfrac{1}{16^{10}} \) |
0.000000001 | 0.00000000001455192 | \( \dfrac{1}{16^9} \) |
0.00000001 | 0.0000000002328306 | \( \dfrac{1}{16^8} \) |
0.0000001 | 0.00000000372529 | \( \dfrac{1}{16^7} \) |
0.000001 | 0.00000005960464 | \( \dfrac{1}{16^6} \) |
0.00001 | 0.0000009536743 | \( \dfrac{1}{16^5} \) |
0.0001 | 0.00001525879 | \( \dfrac{1}{16^4} \) |
0.001 | 0.0002441406 | \( \dfrac{1}{16^3} \) |
0.01 | 0.00390625 | \( \dfrac{1}{16^2} \) |
0.1 | 0.0625 | \( \dfrac{1}{16^1} \) |
1 | 1 | \( 16^0 \) |
10 | 16 | \( 16^1 \) |
100 | 256 | \( 16^2 \) |
1000 | 4096 | \( 16^3 \) |
10000 | 65536 | \( 16^4 \) |
100000 | 1048576 | \( 16^5 \) |
1000000 | 16777216 | \( 16^6 \) |
10000000 | 268435456 | \( 16^7 \) |
100000000 | 4294967296 | \( 16^8 \) |
1000000000 | 68719476736 | \( 16^9 \) |
100000000000 | 1099511627776 | \( 16^{10} \) |
10進数からr進数への基数変換のアルゴリズム
-
与えられた数値を整数部と小数部とに分かる。
ここでは10進数の59713.059814453125を16進数へ基数変換する例を挙げる。
\[ (59713.059814453125)_{10} = (59713)_{10} + (0.059814453125)_{10} \] -
整数部に連続除法(剰余法)を適用する。
ここで連続除法(剰余法)とは次のことを指す。各桁の値を変換したい基数で割り算し、その余りを記録し、そして割り算の答えの整数部を更に基数で割り算し、その余りを記録し、これを答えがゼロに達するまで繰り返す。答えが循環小数になる場合は適当なところで計算を打ち切る。
\[ \begin{array}{r|l:l} \text{割る数} & \text{割られる数} & \text{余り} \\ \hline 16 & 59713 \\ \hline 16 & 3732 & 1 \\ \hline 16 & 233 & 4 \\ \hline 16 & 14 & 9 \\ \hline & 0 & 14 \rightarrow E \end{array} \] \[ \therefore E941 \] -
小数部に乗算法を適用する。
ここで乗算法とは次のことを指す。各桁の値(小数)を変換したい基数で掛け算し、その答えから整数部を差し引いた値を更に基数で掛け算し、小数部がゼロになるまでこの計算を繰り返す。その際、各桁の乗算ごとに得られた整数部の値を記録する。掛けても掛けても小数部が無くならない場合は適当なところで計算を打ち切る。
\[ \begin{array}{r|l:l} \text{掛ける数} & \text{掛けられる数} & \text{差し引いた整数部}\\ \hline 16 & 0.059814453125 \\ \hline 16 & 0.95703125 & 0 \\ \hline 16 & 0.3125 & 15 \rightarrow F \\ \hline 16 & 0 & 5 \end{array} \] \[ \therefore 0.0F5 \]\( 16 \times 0.95703125 = 15.3125 \)になるが、そこから整数部である15を差し引いて\( 15.3125 - 15 = 0.3125 \)、小数部の0.3125だけを次の「掛けられる数」にする点に要注意。
-
得られた数値の整数部と小数部を足し合わせる。
\[ (E941)_{16} + (0.0F5)_{16} = (E941.0F5)_{16} \]
コメント
コメントを投稿