今回は正の整数を「10進数を2進数に変換する」プログラム作成していきたいと思います。
「10進数から2進数に変換する方法」はたくさんありますが、このページでは2つの方法と、そのプログラムの紹介をしていきたいと思います。
重要なのは考え方です。考え方が理解できれば、他の実装もいくらでも自力で導き出せると思います!
その考え方に力を入れて解説していますので、ちょっと長くなっていますが最後まで読んでいただければ幸いです。
Contents
10進数から2進数への変換
まずは考え方についておさらいしておきましょう。
10進数と2進数
2進数は値の表現方法の1つです。使用される数字は 0
と 1
の2種類のみです(10進数だと 0
から 9
の10種類の数字から構成されます)。
10進数も値の表現方法の1つで、この表現方法が異なるために異なる数字で同じ値を表現することができます。
例えば下記の表のように同じ値を10進数と2進数で表現することができます。
10進数 | 2進数 |
0 | 0 |
1 | 1 |
2 | 01 |
3 | 11 |
4 | 100 |
スポンサーリンク
10進数から2進数への変換とは
続いて10進数から2進数への変換について説明していきます。
10進数は2の冪乗の倍数の足し算で表せる
10進数の正数は必ず下記のように2の冪乗の倍数の足し算として表すことができます。
\(10進数 = a_{N – 1} \times 2^{N-1} + a_{N – 2} \times 2^{N-2} + ・・・+ a_{2} \times 2^{2} + a_{1} \times 2^{1} + a_{0} \times 2^{0} \)
上記を満たす \(a_{N – 1}\) 〜 \(a_{0}\) にはいろんな数字の組み合わせが存在します。
例えば10進数の 5
は、\(a_{1} = 1\)、\(a_{0} = 3\) として下記でも表せますし、
\(5 = 1 \times 2^{1} + 3 \times 2^{0} \)
\(a_{0} = 5\) として下記でも表すことができます。
\(5 = 5 \times 2^{0} \)
ただし、\(a_{N – 1}\) 〜 \(a_{0}\) を 0
もしくは 1
のみに限定すると \(a_{N – 1}\) 〜 \(a_{0}\) の組み合わせは「1つのみ」になります。
例えば 5
の場合は、下記の1つの組み合わせのみです。
\(5 = 1 \times 2^{2} + 1 \times 2^{0} \)
\(a_{N – 1}\) 〜 \(a_{0}\) が 0
の場合も省略せずに書くと下記のようになります。
\(5 = 0 \times 2^{N-1} + 0 \times 2^{N-2} + ・・・ + 1 \times 2^{2} + 0 \times 2^{1} + 1 \times 2^{0} \)
この \(a_{N – 1}\) 〜 \(a_{0}\) を左から順に並べたものが、10進数を2進数に変換した結果になります。
例えば上記の例であれば、
\(5 = 00・・・101 \)
になります。\(N\) は2進数の桁数であり、\(N = 3\) とすると(つまり3桁の2進数で表すと)、結果は下記のようになります。
\(5 = 101 \)
このページでは2進数の一番右側の桁を第 0
桁と呼び、左側に行くにつれて桁が上がっていく(第 1
桁、第 2
桁・・・)前提で解説していきたいと思います。
10進数から2進数への変換とは
ここまでをまとめると、「10進数から2進数への変換」とは、下記と、
\(a_{N – 1} 〜 a_{0}\) の全てが 0
もしくは 1
下記の両方を満たす \(a_{N – 1}\) 〜 \(a_{0}\) の組み合わせを見つけ出すことと言えます。
\(10進数 = a_{N – 1} \times 2^{N-1} + a_{N – 2} \times 2^{N-2} + ・・・+ a_{2} \times 2^{2} + a_{1} \times 2^{1} + a_{0} \times 2^{0} \)
\(a_{n}\) の値が、2進数に変換した時の第 n
桁目の値に対応します。
逆に上式の右辺を計算すれば「2進数から10進数への変換」を行うことができます。
「2進数から10進数への変換」は単に計算すれば良いだけなので簡単ですが、「10進数から2進数への変換」は組み合わせを見つけ出すことが必要なので難易度は高いです。
剰余算と除算を繰り返す方法
では、どのようにして「10進数から2進数への変換」を行えば良いのか?ここについて解説していきます。
考え方
まずは剰余算と除算を繰り返す方法です。
10進数から2進数への変換で紹介した下記の式を用いて2進数への変換の仕方を考えていきましょう。2進数を求めるので、\(a_{N – 1}\) 〜 \(a_{0}\) は 0
もしくは 1
に限定されます。
\( x = a_{N – 1} \times 2^{N-1} + a_{N – 2} \times 2^{N-2} + ・・・ + a_{2} \times 2^{2} + a_{1} \times 2^{1} + a_{0} \times 2^{0} \)
\(x\) は2進数に変換しようとしている10進数とします。
第 0
桁を求める
まず \(a_{0} \times 2^{0}\) 以外の項に注目したいと思います。
\(a_{N – 1}\) 〜 \(a_{1}\) は 0
もしくは 1
ですので、これらは単に2の冪乗の値同士の足し算となります。
つまり、この足算結果は絶対に「偶数」になります。
一方で、\(a_{0} \times 2^{0}\) の結果は 0
もしくは 1
のどちらかです。
ここで思い出していただきたいのが下記の法則です。
- 偶数 + 偶数の結果は必ず偶数になる
- 偶数 + 奇数の結果は必ず奇数になる
つまり、\(a_{0} \times 2^{0}\) 以外の項の和は必ず偶数になることを考慮すれば、下記のことが言えます。
- \(x\) が偶数であれば \(a_{0}\) は偶数、つまり
0
- \(x\) が奇数であれば \(a_{0}\) は奇数、つまり
1
なので、\(x\) が偶数奇数のどちらであるかを調べれば \(a_{0}\) が 0
と 1
のどちらであるかを知ることができます。すなわち、2進数に変換した時の第 0
桁目の値を求めることができます。
C言語だと、x % 2
により 2 の剰余算を行うことで \(x\) が偶数か奇数かを調べることができます(結果が 0
であれば偶数、1
であれば奇数)。
つまり、10進数から2進数に変換しようとしている値に対して % 2
を行うだけで、2進数の第 0
桁(\(a_{0}\))を求めることができます。
第 1
桁以降を求める
では、他の桁はどうやって調べれば良いでしょうか?
これも実は第 0
桁とほぼ同様にして求めることができます。
まず下記の式の両辺を 2 で割ることを考えてみましょう。
\(x = a_{N – 1} \times 2^{N-1} + a_{N – 2} \times 2^{N-2} + ・・・ + a_{2} \times 2^{2} + a_{1} \times 2^{1} + a_{0} \times 2^{0} \)
C言語では整数同士の割り算では小数点以下は切り捨てされますので、それを考慮して結果を考えてみます。
結果は下記のようになります。
\( x / 2 = a_{N – 1} \times 2^{N – 2} + a_{N – 2} \times 2^{N-3} + ・・・ + a_{2} \times 2^{1} + a_{1} \times 2^{0} \)
元々あった \(a_{0} \times 2^{0}\) の部分は 2 で割ると 0.5 もしくは 0 になるので切り捨てされます。
さらにそれ以外の項に関しては冪数が 1 ずつ減ることになります(\(2^n / 2 = 2^{n-1}\))。
ここで \(a_{1} \times 2^{0}\) 以外の項の和は、前述でも解説したように必ず偶数になります(偶数同士の足算)。
ですので、\(x / 2\) が偶数である時には \(a_{1}\) が 0
、奇数である時には 1
になります。
したがって x / 2 % 2
の結果を求めることで \(x\) を2進数に変換した時の第 1
桁の値(\(a_{1}\))を求めることができます。
他の桁に関しても同様です。
つまり、10進数を n
回分 2 で割り算し、その結果に対して % 2
を求めれば、第 n
桁の値を求めることができます。
後はこの処理を左辺が 0
になるまで繰り返せば、10進数から2進数への変換が行えます。
筆算で計算も可能
感の良い方なら気づいているかもしれませんが、実はここまで解説してきた変換方法は、下記の筆算と同じことを行っています。
この筆算でも 2 での剰余算と 2 での除算を繰り返すことで2進数変換していますよね。
同じことを行っているので、当然2進数への変換は筆算で計算してやれば良いです。
ただし2進数に変換できる理由ははここまで私が解説してきた内容になります。なぜこの筆算で2進数変換できるかを理解しておきたい方は、是非今回私が解説してきた内容も覚えておいていただけると幸いです。
スポンサーリンク
スポンサーリンク
プログラム
この剰余算と除算を繰り返して10進数を2進数に変換するプログラムのソースコードは下記のようになります。
下記では変数 x
に格納された値を2進数にした結果を配列 bin
に格納しています。
#include <stdio.h>
#define MAX_BIT 32
int main(void) {
unsigned int x; /* 10進数格納用 */
unsigned int bin[MAX_BIT]; /* 2進数格納用 */
unsigned int n;
unsigned int i;
/* 10進数を格納 */
x = 123456789;
/* 第0桁から値を算出していく */
n = 0;
while (x > 0) {
/* 剰余算で2進数の第n桁を算出 */
bin[n] = x % 2;
/* 除算で第n桁目を切り捨て */
x = x / 2;
/* 次の桁へ */
n++;
}
/* 求めた2進数を表示 */
for (i = 0; i < n; i++) {
/* 第i桁を表示 */
printf("%u", bin[n - 1 - i]);
}
printf("\n");
return 0;
}
最後に2進数を表示する処理では、配列 bin
の格納順の逆順で表示しています。
これは、bin
には下位の桁から順に値を格納するようにしていますので、配列 bin
の格納順そのままで表示すると2進数の各桁の並びが逆順になってしまうからです。
この剰余算と除算を繰り返して2進数を求める方法では、下位の桁から順に値を求めることしかできません。
ですので、上位の桁から順に値を表示するためには、上記のソースコードのように配列等の値を保存しておく変数を用意しておき、全ての桁の値を求めてから表示してやる必要があります。
ここがこの方法の難点だと思います。
ビット演算を用いる方法
次はビット演算を用いて10進数からの2進数を行う方法の考え方とプログラムの紹介をしていきたいと思います。
考え方
ここまではどちらかというと「人間」が10進数を2進数に変換する考え方で2進数への変換を行ってきました。
それに対して次に解説するのは「コンピュータの性質」を利用した2進数への変換方法になります。
コンピュータ内部で扱うデータは 0
と 1
のみ
実は、コンピュータが内部で扱うデータは 0
もしくは 1
の値のみです。
まさに2進数の状態でデータを扱っているのです。
こう聞くと意外と感じるかもしれません。実際にコンピュータは10進数の値を入力したり表示したりすることもできますし、さらには画像を表示したり動画を再生したりすることもできます。
これはコンピュータ内部で扱っている 0
もしくは 1
の値を画面に表示するような時に、10進数や画像などの人間が理解しやすい形式に変換しているだけです。
コンピュータが内部で扱っている値はあくまでも 0
もしくは 1
のみです。
この辺りは下記ページでも解説していますので興味がある方は是非読んでみてください。
コンピュータが扱うデータについて解説ここで言いたいことは、10進数もコンピュータ内部では2進数で扱われているということです。
なので、単に2進数の各桁が 0
もしくは 1
のどちらなのかを調べるだけで10進数から2進数への変換を実現することができます。
ただ、この各桁が 0
と 1
のどちらであるかを調べる直接的な方法はC言語には用意されていませんので、いくつかの演算を組み合わせて行う必要があります。
ここで利用するのがビット演算とシフト演算です。
このビット演算とシフト演算については下記で解説していますので、詳しく知りたい方はこちらを参照していただければと思います。
C言語のビット演算(論理演算)について解説&
演算を用いた10進数から2進数への変換
まず利用するのがビット演算の1つである &
演算です。
&
演算を利用することで、10進数を2進数で考えた時の、特定の桁が 0
と 1
のどちらであるかを調べることができます。
具体的な方法は下記の通りです。
まず10進数から2進数に変換したい値を格納した変数(x
とします)と、2進数で考えたときに、ある桁(第 n
桁とします)のみ 1
になる値を格納した変数(y
とします)を用意します。
そしてこの2つの変数 x
と y
に対して &
演算を行います。
a = x & y;
この結果の変数 a
には下記の値が格納されることになります。
0
:x
を2進数として考えた時の第n
桁が0
の場合0
以外:x
を2進数として考えた時の第n
桁が1
の場合
ですので、n
を 0
から特定の桁数まで増やしながら下記を繰り返すことで、10進数 x
を2進数に変換することができます(下記では第 N - 1
桁目まで n
を増やしています)。
n
を0
とする- 2進数で考えたときに第
n
桁のみが1
となる値を算出する - その算出結果と
x
との&
演算を行う &
演算の結果に応じて下記のように2進数のn
桁目の値を設定0
:&
演算の結果が0
の場合1
:&
演算の結果が0
以外の場合
n
を1
増やすn
がN
以下なら 2. に戻る。それ以外は終了
シフト演算を用いた特定の桁のみを 1
とする値の算出
では「2進数で考えたときに第 n
桁のみが 1
となる値を算出する」にはどうすれば良いでしょうか?
これは「シフト演算」を用いれば簡単に行うことができます。
シフト演算では、2進数の各桁を、指定した桁数分左方向 or 右方向にそのままシフトすることができます。
ですので、2進数で考えたときに第 0
桁目のみが 1
となる値(10進数で考えると 1
)を用意し、その値を n
桁分左方向にシフトすれば上記の値を算出することができます。
左シフトする演算子は <<
ですので、具体的には下記の処理で、上記の値を算出することができます。
y = 1 << n;
シフト演算についても詳細は下記ページで解説していますので、詳しく知りたい方は是非読んでみて下さい。
C言語のビット演算(論理演算)について解説スポンサーリンク
スポンサーリンク
プログラム
この剰余算と除算を繰り返して10進数を2進数に変換するプログラムのソースコードは下記のようになります。
下記では変数 x
に格納された値を2進数にした結果を配列 bin
に格納しています。出力される2進数は必ず32桁になります。
#include <stdio.h>
#define MAX_BIT 32
int main(void) {
unsigned int x; /* 10進数格納用 */
unsigned int bin[MAX_BIT]; /* 2進数格納用 */
unsigned int n;
unsigned int i;
unsigned int a; /* 特定の桁のみ1の値格納用 */
/* 10進数を格納 */
x = 123456789;
/* 第0桁から値を算出していく */
n = 0;
while (n < MAX_BIT) {
/* 第n桁のみ1の値を算出 */
a = (unsigned int)1 << n;
/* &演算で第n桁の値取得 */
if ((x & a) == 0) {
bin[n] = 0;
} else {
bin[n] = 1;
}
/* 次の桁へ */
n++;
}
/* 求めた2進数を表示 */
for (i = 0; i < n; i++) {
/* 第i桁を表示 */
printf("%u", bin[n - 1 - i]);
}
printf("\n");
return 0;
}
この方法では「剰余算と除算を繰り返す方法」と違って、上位の桁から値を算出することができます。
この場合はわざわざ配列に値を格納して後から表示しなくても、求めた桁から表示してやれば、自然と上位の桁から値が表示されていきます。
#include <stdio.h>
#define MAX_BIT 32
int main(void) {
unsigned int x; /* 10進数格納用 */
unsigned int n;
unsigned int i;
unsigned int a; /* 特定の桁のみ1の値格納用 */
/* 10進数を格納 */
x = 123456789;
/* 第31桁から値を算出していく */
n = MAX_BIT - 1;
while (1) {
/* 第n桁のみ1の値を算出 */
a = (unsigned int)1 << n;
/* &演算で第n桁の値取得 */
if ((x & a) == 0) {
printf("0");
} else {
printf("1");
}
/* 第0桁を表示したら終了 */
if (n == 0) {
break;
}
/* 次の桁へ */
n--;
}
printf("\n");
return 0;
}
その他のプログラム
10進数から2進数への変換を行う上で重要になるのは「10進数は2の冪乗の和の形式で表せる」「コンピュータ内部では2進数で値が扱われる」の2点だと思います。
この2点を理解しておけば、他にもいろんな実装で10進数から2進数への変換を行うことができます。
最後にその例をいくつか紹介しておこうと思います。
2の冪乗の引き算を繰り返して2進数変換
下記がソースコード例になります。「10進数は2の冪乗の和の形式で表せる」ことを利用して2の冪乗の引き算を繰り返すことで2進数変換を行っています。
#include <stdio.h>
#define MAX_BIT 32
int main(void) {
unsigned int x; /* 10進数格納用 */
unsigned int a; /* 2の冪乗格納用 */
unsigned int n;
unsigned int i;
/* 10進数を格納 */
x = 123456789;
/* 第31桁から値を算出していく */
n = MAX_BIT - 1;
while (1) {
/* 2のn乗を計算 */
a = 1;
for (i = 0; i < n; i++) {
a = a * 2;
}
if (x >= a) {
printf("1");
x = x - a;
} else {
printf("0");
}
/* 第0桁を表示したら終了 */
if (n == 0) {
break;
}
/* 次の桁へ */
n--;
}
printf("\n");
return 0;
}
スポンサーリンク
2の冪乗の計算とビット演算で2進数変換
下記がソースコード例になります。ビット演算を用いる方法の最後に紹介したものとほぼ同じですが、こちらはシフト演算を用いずに2進数変換を実現しています。
#include <stdio.h>
#define MAX_BIT 32
int main(void) {
unsigned int x; /* 10進数格納用 */
unsigned int n;
unsigned int i;
unsigned int a; /* 特定の桁のみ1の値格納用 */
/* 10進数を格納 */
x = 123456789;
/* 第31桁から値を算出していく */
n = MAX_BIT - 1;
while (1) {
/* 2のn乗を計算 */
a = 1;
for (i = 0; i < n; i++) {
a = a * 2;
}
/* &演算で第n桁の値取得 */
if ((x & a) == 0) {
printf("0");
} else {
printf("1");
}
/* 第0桁を表示したら終了 */
if (n == 0) {
break;
}
/* 次の桁へ */
n--;
}
printf("\n");
return 0;
}
まとめ
このページでは正の整数を10進数から2進数に変換する方法の考え方およびプログラムの解説を行いました。
おそらく一番有名な方法は「剰余算と除算を繰り返す筆算」だと思います。ただこの方法を知っている方でも、「なぜこの方法で2進数に変換できるのか?」の理由を知らない方も多いのではないでしょうか?
この理由や考え方を理解しておけば、2進数変換を行う他の方法や実装も自力で考え出せるようになります。このページでは特にこの考え方の解説に力を入れていますので、2進数変換のプログラミングできる方にも是非じっくり読んでいただければと思います。