Edited at

数値の構造をおさらいしよう(float,double)

More than 3 years have passed since last update.

doubleとfloat

doubleとfloatは次のように呼ばれています。

double(倍精度浮動小数点型)

float(浮動小数点型)

そもそも浮動小数点型ってなんでしたっけ。

浮動小数点型

符号部(正負) + 指数部(10^) + 仮数部(数値) から構成される数値です。


符号部 : 数値がマイナスかプラスかを示すための部分


指数部 : 数値の大きさを示す部分


仮数部 : 値を格納する部分

となっております。なので32bitといえども、保存できる値の領域は決まっておるわけであります。

floatとdoubleの違い

構成
符号部
指数部
仮数部

float
1bit
8bit
23bit

double
1bit
11bit
52bit

floatは32bit(4byte),doubleは64bit(8byte)となっております。

doubleでは倍精度ということでfloatの倍のサイズを持っていることがわかります。

つまりデータとしてはdoubleのほうが2倍大きいのです。

たとえばfloatではこのように32bitの値であっても値として使える部分が

23bitと限られており、24bit目に値を入れちゃったりすると変な挙動をすることがわかります。

例えばこんな実験をしてみましょう。

int(32bit)でどんどん2進数でのbitフラグを立てていきます。24bitまで


Test


int target{0};

for(int i = 0 ;i < 25;i++)
{
target |= 1 << i;
printf("%d\n",target);
}

printf("%f\n",(float)target);

return 0;



結果

1

3
7
15
31
63
127
255
511
1023
2047
4095
8191
16383
32767
65535
131071
262143
524287
1048575
2097151
4194303
8388607
16777215
33554431
33554432.000000 // !! 最後の値がfloatにした瞬間変わっている


となりました。最後のintのtargetの値は33554431でしたが、これをfloatにキャスト値が変わってしまってますよね。

これはどういうことでしょうか。2進数表示に変換してみましょう


2進数表示

1111111111111111111111111 // <= 33554431 (24桁目まで1)

10000000000000000000000000 // <= 33554432 (25桁目のみ1)

これはどういうことでしょうか。floatでは仮数部が23bit、つまり数値として扱えるのは23bitまでなので

もともと24bitまで値が入っているintの値をキャストすると値が溢れてしまったということです。

たしかにfloatが23bitまでしか扱えないことがわかりましたね。

なので大きな値や数値の多いいbitフラグを扱う時はdoubleで行うべきであることがわかります。

doubleなら52bitまで扱えますからね。その分データは倍になってしまいますが。

普段intで32bitまで数値が扱えている分、ふとしたときにこういうワナにはまってしまわぬよう、覚えておきましょう。