はじめに
ITパスポートや基本情報などでよく出てくる10進数を2進数に変換する計算。
その中で小数部に関する計算を掘り下げます。
参考書などでは、小数点以下の値を基数で掛け算し小数部がなくなるまでそれを続ける方法が主に用いられていると思います。
2 * 0.375 = 0.75
2 * 0.75 = 1.5
2 * 0.5=1.0
掛けた結果、整数部が1となった箇所はその時点に値があることを意味し、出てきた整数部を上から順に並べる。
すると011
という値が求まり、これが0.375を2進数の表記ということになる。
しかしどの参考書も計算方法は教えてくれるものの、
なぜこの方法で変換できるのかという点について説明がない...
ということで、整数部の計算に続き小数部の計算方法について考えてみる。
尚、今回も数学の高度な知識は不要です。
2進数の小数とは
一見難しく感じますが、実は簡単です。
2進数は桁が上がるごとに2倍となっていきますよね。
これを逆の向きで考えてみましょう。
桁が下がるごとに値が半分になっていっています。
では2進数の1桁目の値である1
の半分は?
・・・
そう0.5
です。
ということは、2進数の0.1は10進数の0.5に相当するということです。
先に述べたように2進数は桁が上がるごとに2倍となっていきます。
この法則は揺るぎませんから、小数であろうと同様です。
0.5 * 2 = 1
結果、2進数1桁目の値である1を求めることができました。
桁が変わっても考え方は同じ
では0.01はどうなるでしょうか。
これも0.5を半分にした値、即ち0.25
となります。
では0.001は?
これも0.25を半分にした値、即ち0.125
となります。
といったように値がどんどん半分になってるのです。
そしてそれぞれ2倍にしていくことで、元の値に戻る。
つまり、桁が上がるということです。
小数部の計算はこの、2倍にすると桁が上がるという性質を利用して、
該当するbitの位置の値があるかを判定しているのです。
以下、2進数と10進数の対応関係となる簡易表になります。
2進数 | 10進数 | 整数部に達するために必要な計算 |
---|---|---|
0.1 | 0.5 | 0.5 × 2 |
0.01 | 0.25 | 0.25 × 2 × 2 |
0.001 | 0.125 | 0.125 × 2 × 2 × 2 |
仕組み
基数を掛けて、整数部に発生した値を並べるとそのまま2進数のbit表現になるって訳わかんないですよね。
でも実は非常にシンプルです。
これは単に桁上がりを発生させているのです。
繰り返しの説明となりますが、
0.5
に2を掛けたらいくつになるでしょうか?
そう1
です。
では0.7に2を掛けたら?
1.4
です。
0.4に2を掛けたら?
0.8で1に達しません。
つまり、0.5以上の値を掛ければ整数部に値が出現するのです。
当たり前のことに思いますが、
この考え方を利用して、該当するbitの値の有無を判定しているのです。
では2進数0.01
の場合はどうでしょう。
これは10進数でいうところの0.25でしたね。
この値が整数部に達するには4を掛ける必要がありますね。
0.25 * 2 = 0.5
⇒整数部に値が出現しなかったため、小数点第1位に値無し
0.5 * 2 = 1
⇒整数部に値が出現したため、小数点第2位に値有り
先の説明で0.25が整数部に達するには4を掛けないといけないと言いました。
先の計算を一つの式に纏めると以下のようになります。
0.25 * 2 * 2 = 1
数学には「交換法則」と呼ばれる法則があります。
これは、加法や乗法において足される数(掛けられる数)と足す数(掛ける数)を入れ替えてもその和や積は変わらないというもの。
簡単に言えば、どの順番で掛けたって結果は変わらないということです。
今回の例を基に言うならば0.25
に対して2を2回掛けようが、先に2 * 2
を求めて4を1回掛けようが同じということです。
つまり2を2回掛けることで整数部が出現する値ということは、
0.25以上、0.5未満であるということになります。
0.25 ≧ n ⋖ 0.5
「えっ、0.5以上の値だって2を2回掛けたら整数部が出現するけど?」と思うかもしれませんが、その場合2を1回掛けたタイミングで整数になりますから、その前に引っかかる訳です。
そして引っかかった値は整数部をそぎ落して、小数部だけで計算を進めていくため、0.5以上の値に対して2回乗算するということは起こり得ないということになります。
整数部をそぎ落として小数部だけで計算を進めるのってどういう理屈なの?
この点もモヤっと来ないでしょうか?(私はモヤっとしました)
勝手に整数をそぎ落として計算進めてるけど、
後の計算に何か影響しないの?という漠然とした不安を感じました。
数学が得意な人なら、なぜそぎ落としてもいいのかパッと分かるのかもしれませんが、
決して数学に精通していない自分はどこかスッキリしませんでした。
改めて以下の表を確認しましょう。
2進数 | 10進数 | 整数部に達するために必要な計算 |
---|---|---|
0.1 | 0.5 | 0.5 × 2 |
0.01 | 0.25 | 0.25 × 2 × 2 |
0.001 | 0.125 | 0.125 × 2 × 2 × 2 |
「整数部に達するための必要な条件」を新たに加えます。
2進数 | 10進数 | 整数部に達するために必要な計算 | 整数部に達するために必要な条件 |
---|---|---|---|
0.1 | 0.5 | 0.5 × 2 | n ≧ 0.5 |
0.01 | 0.25 | 0.25 × 2 × 2 | n ≧ 0.25 |
0.001 | 0.125 | 0.125 × 2 × 2 × 2 | n ≧ 0.125 |
何度も同じことを言って申し訳ないですが、
2(基数)を1回掛けて整数部に達するには0.5以上でないとダメなわけです。
つまり、0.5未満の値に2を掛けようが、小数点以下に留まるということです。
具体的な数値で見ていきましょう。
0.75
という10進数の値を2進数に変換します。
0.75 * 2 = 1.5
⇒整数部に値が出現=小数点第1位に値有
#1.5から1を取り除き、残りの0.5だけで計算を進める
0.5 * 2 = 1.0
⇒整数部に値が出現=小数点第2位に値有
#小数部が0となったため計算完了
答え:0.11
0.75という値は0.5よりも大きいですから、
最初の乗算で整数部に達しますね。
そして0.5という謎の数字が出現しました。
感覚で「0.5を引いた残りの値なんだな」ということが分かりますが、
しかしなぜそうなるのかを説明しろと言われると難しい...
そこで0.75という値を表の値をもとに2つの要素に分解してみましょう。
0.5 + 0.25
そしてこれに対して2を掛けます
(0.5 + 0.25)2
(0.5 * 2) + (0.25 * 2)
#()内の式をそれぞれ独立した式で結果を求めます
0.5 * 2 = 1
0.25 * 2 = 0.5
この結果からわかるように、2を掛けた整数部にはみ出した1という値は綺麗に0.5の要素だけを抜き出しています。
というのもこれを2で割ってみると0.5
という値になります。
基数変換における小数部の計算は「桁上がり」を利用することで、特定の値の有無を求める方法でしたね。
2進数においては2を掛けることで桁が上がっていきます。
だから、整数部に達した(桁上がりした)1という値の正体は0.5な訳です。
つまり、整数部をそぎ落とすということは元の値から0.5を引いているのに等しいのです※
小数第1位の場合
小数第2位の場合は0.25、第3位の場合は0.125が引かれる
そして残った0.5ですが、これは元の値に2を掛けて出てきた値ですから、
本当の姿に戻すには2で割ってあげる必要がありますね。
つまり0.25
です。
このことから小数点以下の値は、元の値に0.5を引いて残った値であることがわかります。
0.25
の値が整数部に達するためには、
0.25 × 2 × 2
の計算が必要になりますね。
ただ、わざわざ最初からやり直さなくても、
先の計算から既に0.25 × 2
の計算は完了している訳です。
なので、再度2を掛ければ計算が成り立つ訳ですね。
小数部がなくなるまで計算を続ける理由
小数部がなくなるということは、全ての値が桁上がりしたということになります。
すべての値が桁上がりしたということは、全ての値が小数点以下の対応するbitに収まったということです。
ちなみに必ずしもきれいに収まらないケースもあります。
例えば0.7という値を2進数で表そうとしても、途中で循環小数となってしまい、終わりが来ません。
このように10進数で簡単に表現される値が2進数ではうまく表現できなくなってしまうという点が面白いですね。
終わりに
今回書いたものを振り返ってみると凄く当たり前のことしか書いてないのですが、
実際参考書などでこういった計算方法が出てくると頭がこんがらがってしまいます。
恐らくその原因は、整数部と小数部で勝手が変わってくるためだと思います。
整数部の場合、1,2,3,4,5と数値の間隔は10進数と同じです。
異なるのはそれをどういった桁表現にするかといった所です。
一方で小数部は数値の間隔自体が変わっています。
結果、10進数の小数で表現できる値が2進数ではうまく表現できなくなってしまうということに繋がる訳ですね。