Javaのバイナリをいじっていて、floatやdoubleの格納方法が気になったので以下のようなソースコードで勉強をしていました。
int main() {
union {
double d;
float f;
unsigned char c[8];
} uni;
printf("入力:");
scanf("%lf", &uni.d);
printf("d = %lf\n", uni.d);
dump(uni.c, 8);
sdumpb(buff, uni.c, 8);
exponent = (cast_n(&uni.c[4], 4) & 0x7FF00000) >> 20;
printf("指数部:%d(%d)\t仮数部:%s\n", exponent - 1023, exponent, &buff[12]);
uni.f = uni.d;
printf("f = %f\n", uni.f);
dump(uni.c, 4);
dumpb(uni.c, 4);
sdumpb(buff, uni.c, 4);
exponent = (cast_n(&uni.c[2], 2) & 0x7F80) >> 7;
printf("指数部:%d(%d)\t仮数部:%s\n", exponent - 127, exponent, &buff[9]);
return 0;
}
ところが、**scanf
から入力したはずのdouble
**が小数点以下6桁までしか表示されないのです。
入力:0.1234567890123456789
d = 0.123457
3f bf 9a dd 37 46 f6 5f
00111111 10111111 10011010 11011101 00110111 01000110 11110110 01011111
指数部:-4(1019) 仮数部:1111100110101101110100110111010001101111011001011111
f = 0.123457
3d fc d6 ea
00111101 11111100 11010110 11101010
指数部:-4(123) 仮数部:11111001101011011101010
これじゃ **double
とfloat
**の値を見比べたいのに比較にならないじゃないの!
ということであちこちググってみても、**%lf
**指定すればええねん。というような答えしか無い。
最終的に以下にたどりついてスッキリ。
IBM Knowledge Center - fprintf()、printf()、sprintf() - データのフォーマット設定と書き込み
e E f F デフォルトの precision は 6。precision が 0 または後ろに数値を伴わずに表示されたピリオドの場合は、小数点は出力されない。
つまり、小数点以下は6桁がデフォルト。
しかし以下の記載は怪しいデス。
g G すべての有効数字が出力される。
%g
を指定してもVC2008のCL.exeでも、bcc32.exe(5.5と10.2)でもフル桁表示されませんでした。
gccやccならちゃんと表示されるのかな。
なので結局、printfで小数点フル桁ほしい時は
printf("%.16f", value);
とかやるのがベストなようです。
冒頭のソースコードの参考元:
浮動小数点数の内部表現(IEEE) - Wakaba Programming School