Version 12.05
double の中身・指数部編
「では今回はたぶんかなり難しい、 double の中身について」
『う”〜』
「まず、前回の関数でいくつか試しに出力してみます」
void Use_OutputDoubleBit()
{
OutputDoubleBit( 1.0 );
OutputDoubleBit( 0.1 );
OutputDoubleBit( 0.5 );
}
00111111 11110000 00000000 00000000 00000000 00000000 00000000
00000000 1.00000000000000000000
00111111 10111001 10011001 10011001 10011001 10011001 10011001
10011010 0.10000000000000001000
00111111 11100000 00000000 00000000 00000000 00000000 00000000
00000000 0.50000000000000000000
「入りきらないから改行入れてあるからね」
『一番後ろのが元の値ね。それにしても……なんか法則性全然ないね。
1.0 と 0.1 って似そうなのに全然違う』
「特に 0.1 はね。この辺が誤差が出る理由」
『やっぱり難しそう……』
「だから、ひとつひとつ見ていくね。まず、一番左側のビットについて。こ
れは符号で、プラスだと 0 、マイナスだと 1 になります」
OutputDoubleBit( 1.0 );
OutputDoubleBit( -1.0 );
00111111 11110000 00000000 00000000 00000000 00000000 00000000
00000000 1.00000000000000000000
10111111 11110000 00000000 00000000 00000000 00000000 00000000
00000000 -1.00000000000000000000
『これはわかりやすいね』
「これはね」
『う”』
「次に double の中で一番シンプルな数、 2.0 について見てみます」
OutputDoubleBit( 2.0 );
01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 2.00000000000000000000
『うわ、ホントだ。ほとんどゼロ! でも 2 が一番シンプルってどういう
こと? かなり変すぎ』
「 2 が一番シンプルなのは、浮動小数点は 2 が基本になってるから。まず
は、この 2.0 を使って指数部について見てみます」
『指数部って、 10 をいくつ掛けるかってゆーのだったよね』
「そう……なんだけど、実際には 10 じゃなくて、 2 なんです」
『 2 ……?』
「上の 2.0 のを例に、指数部の部分を見てみます」
_______ ____
01000000 00000000 00000000 00000000 00000000 00000000 00000000
00000000 2.00000000000000000000
「 _ が付いてる部分が指数部。つまり、 2.0 の指数部は」
1000000 0000
「ってこと」
『これが 2 を…… 1 個掛けてるってこと?』
「そう、これが 2 を 1 個掛けてる場合。だから 2.0 。でも……もうひと
つ 2 を掛けて 4.0 の場合はこうなります」
_______ ____
01000000 00010000 00000000 00000000 00000000 00000000 00000000
00000000 4.00000000000000000000
『あ、想像と違った……』
「きっとそうだと思った。この場合の指数部は」
1000000 0001
「ってなります。同じく 8.0 の場合は」
_______ ____
01000000 00100000 00000000 00000000 00000000 00000000 00000000
00000000 8.00000000000000000000
「 16.0 の場合は」
_______ ____
01000000 00110000 00000000 00000000 00000000 00000000 00000000
00000000 16.00000000000000000000
『って、これって int とかと同じ数え方じゃない!』
「そう、まとめると」
1000000 0000 : 2.0
1000000 0001 : 4.0
1000000 0010 : 8.0
1000000 0011 : 16.0
『つまり、 2 を何個掛けるか、が int とかと同じ方法で入ってるわけね』
「だいたい合ってるかな」
『だいたい?』
「最初の 1 はなんだと思う?」
『 int だと、最初の 1 ってマイナスって意味だったよね、でもなんか違う
し……』
「これは、 1.0 、 0.5 、 0.25 を見ればわかると思うよ」
_______ ____
00111111 11110000 00000000 00000000 00000000 00000000 00000000
00000000 1.00000000000000000000
_______ ____
00111111 11100000 00000000 00000000 00000000 00000000 00000000
00000000 0.50000000000000000000
_______ ____
00111111 11010000 00000000 00000000 00000000 00000000 00000000
00000000 0.25000000000000000000
「これをさっきのとまとめると次のようになります」
0111111 1101 : 0.25
0111111 1110 : 0.5
0111111 1111 : 1.0
1000000 0000 : 2.0
1000000 0001 : 4.0
1000000 0010 : 8.0
1000000 0011 : 16.0
『あ、普通に増えてるだけ…… unsigned ってことね。でも……』
「 2.0 を 2 で割ったら?」
『 1.0 ……それを 2 で割ったら 0.5 、 0.5 を 2 で割ったら 0.25 !』
「そういうこと。もう少し正確に書くと」
...
0111111 1101 : 2 の -2 乗
0111111 1110 : 2 の -1 乗
0111111 1111 : 2 の 0 乗
1000000 0000 : 2 の 1 乗
1000000 0001 : 2 の 2 乗
1000000 0010 : 2 の 3 乗
1000000 0011 : 2 の 4 乗
...
「ってなります」
『そういえば 2 の 0 乗は 1 だったね』
「だから、ビット的に一番大きいのと小さいのを見てみると、こうなりま
す」
0000000 0000 : 2 の -1023 乗
...
0111111 1101 : 2 の -2 乗
0111111 1110 : 2 の -1 乗
0111111 1111 : 2 の 0 乗
1000000 0000 : 2 の 1 乗
1000000 0001 : 2 の 2 乗
1000000 0010 : 2 の 3 乗
1000000 0011 : 2 の 4 乗
...
1111111 1111 : 2 の 1023 乗
『うわ、すごい大きな数……』
「 2 の 1023 乗だと、10進数で 0 が 300 個強付くくらいの数」
『うわ……』
「だから、浮動小数点なら桁そのものについてはそれほど気にしなくていい
かな」
『 int の比じゃないわね。でも……そういう大きな桁だと、誤差が出ちゃ
うわけよね』
「ううん、今見たように 2 の乗数は絶対に誤差は出ないから」
『あ、そっか、 2 をいくつ掛けるかってだけだから、誤差とか出ないん
だ。それに 0.5 とか 0.25 とか、 2 で割っていく数も誤差は出ないね』
「そういうこと。というわけでまとめ」
・最初のビットはプラス/マイナスのフラグ。
・2番目のビットから12番目のビットは指数。
2 の何乗か、を表している。
unsigned int に近い形式で表現。
ただし最初から 1023 が足された状態。
・ 2 の乗数の数は誤差が出ない。
... 0.125 0.25 0.5 1 2 4 8 16 ...
「こんなところかな」
『じゃ、次回は仮数部の話ね!』
/*
Preview Next Story!
*/
『……なんか今日のだけだとそんな難しくないけど』
「ひとつずつ追っていけばね」
『いっぱい出てくるとわかんなくなる?』
「というより、ビットの並びを頭の中で数値に変換するとかすると」
『げ、それは難しそう』
「特に仮数部の計算は難しいよー」
『げげ!』
「というわけで次回」
< Version 12.06 double の中身・仮数部編 >
『につづく!』
「って言っても、頭の中で変換、なんてまず必要ないんだけど」
『……勉強する意味ないし』