浮動小数点の精度の確認
C言語における浮動小数点の精度を確認してみた。検証した環境は、
プロセッサ | Intel Core2 Duo |
OS | Ubuntu 8.04 AMD64 |
コンパイラ | gcc version 4.2.3 |
(OSはVMwareの仮想環境で、ホストOSはFedora 8 x64)
この環境で次のプログラムを実行した。
#include <stdio.h> #include <math.h> #include <float.h> main() { float f; double d; long double l; printf("sizeof(float) = %d bytes (%d bits)\n", sizeof(f), sizeof(f)*8); printf("float\t\t%d\t%d\t%d\t%d\t%E\t%E\n", FLT_RADIX, FLT_MIN_EXP, FLT_MAX_EXP, FLT_MANT_DIG, FLT_MIN, FLT_MAX); printf("sizeof(doule) = %d bytes (%d bits)\n", sizeof(d), sizeof(d)*8); printf("double\t\t%d\t%d\t%d\t%d\t%E\t%E\n", FLT_RADIX, DBL_MIN_EXP, DBL_MAX_EXP, DBL_MANT_DIG, DBL_MIN, DBL_MAX); printf("sizeof(long doule) = %d bytes (%d bits)\n", sizeof(l), sizeof(l)*8); printf("long double\t%d\t%d\t%d\t%d\t%LE\t%LE\n", FLT_RADIX, LDBL_MIN_EXP, LDBL_MAX_EXP, LDBL_MANT_DIG, LDBL_MIN, LDBL_MAX); printf("\n"); // 3.14159 26535 89793 23846 26433 83279 50288 f = 3.1415926535897932384626433832795028; printf("f = 3.1415926535897932384626433832795028;\t= %.34E\n", f); d = 3.1415926535897932384626433832795028; printf("d = 3.1415926535897932384626433832795028;\t= %.34E\n", d); d = 3.1415926535897932384626433832795028l; printf("d = 3.1415926535897932384626433832795028l;\t= %.34E\n", d); l = 3.1415926535897932384626433832795028; printf("l = 3.1415926535897932384626433832795028;\t= %.34LE\n", l); l = 3.1415926535897932384626433832795028l; printf("l = 3.1415926535897932384626433832795028l;\t= %.34LE\n", l); printf("\t\t\t\t\t\t 3.1415926535897932384626433832795028\n"); }
実行結果は以下の通り。
sizeof(float) = 4 bytes (32 bits) float 2 -125 128 24 1.175494E-38 3.402823E+38 sizeof(doule) = 8 bytes (64 bits) double 2 -1021 1024 53 2.225074E-308 1.797693E+308 sizeof(long doule) = 16 bytes (128 bits) long double 2 -16381 16384 64 3.362103E-4932 1.189731E+4932 f = 3.1415926535897932384626433832795028; = 3.1415927410125732421875000000000000E+00 d = 3.1415926535897932384626433832795028; = 3.1415926535897931159979634685441852E+00 d = 3.1415926535897932384626433832795028l; = 3.1415926535897931159979634685441852E+00 l = 3.1415926535897932384626433832795028; = 3.1415926535897931159979634685441852E+00 l = 3.1415926535897932384626433832795028l; = 3.1415926535897932385128089594061862E+00 3.1415926535897932384626433832795028
以下、考察。
4倍精度の実装が寂しい
4倍精度の仮数部の64ビットしか無い。フル実装であれば112ビットであるはずだが。4倍精度では変数として16バイトを占有するが実際に使わるのは64ビット+16ビット=10バイトだけということになる。IEEEの定義では64ビット(8バイト)を超えた実装は全て4倍精度と呼べるらしいので、規格には合っているようだが。これにより、本来4倍精度では仮数部の精度が10進33桁ある筈だが、19桁程しかない。倍精度の15桁よりも僅か多いだけ。それで、8バイトも余計に使うのは投資対効果に見合うか? さて、どうしたものか。
仮数部が64ビットしかないのはIntel Core2アーキテクチャの影響か?(未確認)
4倍精度の定数には“l”が必要
変数を4倍精度で定義しても式の中で定数を使う場合、“l”をつけないと倍精度扱いになってしまい、仮数部の精度が落ちる。