留年戦記

留年と工学と人間関係と毎日戦っている人のブログです. 今年は留年回避済み.プロマネのお勉強中.留学試みたりTOEICの得点向上を試みたり.普通に学校の勉強を頑張ったり工学(プログラミングも回路も)について学んでみたり.時々レーザーカッターのパラメータを記事にしてます.

【C言語】floatとdoubleで計算したら計算結果が異なる!誤差が…!の前置き〈進数その2〉

元気いっぱい,今日も頑張って記事を書くぞ~!と意気込んでいるあこさんです.

さて,前回の続きです.

 

aconote.hatenablog.com

 

4,10進数をN進数に変換

昨日の逆です.

これ,やり方を知らないと結構厄介です.

仮に18という10進数の数があったとします.

これを2,8,16進数へと変換しようと思います.

まず解答から.

2進数=10010(2)

8進数=22(8)

16進数=12(16)

となりますね.

 

さて,ここから本題.計算の仕方.

「18」という変換したい数に対してN(進数の数)で割ります.

で,整数の商となるように計算して余りを出していきます.

余りを最後に出た方から読めば変換されたものになります.

 

というわけで実践.

18/2=9...0

9/2=4...1

4/2=2...0

2/2=1...0

1/2=0...1

下から上に余りを読んで10010.なっていますね.

商が0になるまでやりましょう.

 

次,8進数.

18/8=2...2

2/8=0...2

下から22.合ってる.

 

次16進数

18/16=1...2

1/2=0...1

下から12.合ってる.

 

と,こんな感じに計算をすると変換が簡単にできます.

 

5,2進数から8進数

ここからは豆知識.

2進数って,一けたに対し2種類の数字を使えることから2の乗数個の表現が可能です.

そして8進数の場合は1桁で8種類の数字を使える.これは2の3乗.

つまり,2進数の3桁=8進数の1桁となります.

ので,1の位から3桁ずつ切っていきそれぞれの区間で10進数に一度直す.それを8進数に直して並べれば変換ができる!のです!

 

100111という2進数があったとして,100 | 111と分けられます.

それぞれ,4|7であることから返還後は47となるとわかりますね.

 

6,2進数から16進数

同様に16=2^4であることから2進数4桁=16進数1桁である.

ので,1101010こういう数列に対してまず区切る.

110 | 1010となる.のでそれぞれを10進数に直す.

6 | 10となる.これをそれぞれ16進数に対応する数に直す.

よって,6Aとなる.

 

7,実は一体一対応ではない.

これが本題です.

感の良い方はもうその1の時には気づいていたかもしれませんが10進数で表せる数と2進数で表せる数は1対1対応ではありません.

というのも小数点問題です.

1/2...1/4...1/8でしか2進数は小数点以下を表現できません.

桁が少なければ少ないほど雑になりますね….

0.1という数を2進数に変換すると…

0000 0000 . 0001 1001 1001 1001 1001 1001 ........ となります.

このあとずっと1001が続いていきます.

でこれを再度10進数に戻すと…0.099999964237213134765625と,0.1に戻りません.

 

8,PCによる誤差の発生

そして結論です.

コンピュータ内はすべて2進数で表されています.

よって,上のような数値を入れたとき一度2進数に変換されます.

で10進数に再変換して戻ってきたときには…

となります.

これが誤差の正体です.

そして,これは桁数が少なければ少ないほど大きい誤差となります.

コンピューターで変数に0.1を代入し,あとからその変数ないの数字が0.1であるかみたいなものを聞くと0.1ではないと答えることがあります.

この現象もすべてこの「誤差」によるものなのです.

 

いやぁ,いやですよね.1対1に写像してくれない像なんて.

というわけで進数変換について前置きは理解できたでしょうか….

最後の結論さえ理解出来れいれば問題ありません.

次回,次々回あたりでfloatとdoubleの話を書きますのでもしよければお付き合いくださいませ.