制作日記

こういうの作った方が、逃げにくいじゃない

小数の誤差

http://ariarienlol.blog55.fc2.com/blog-entry-761.html

これはハードとかプログラミング言語の仕様なんで……。

浮動小数の10進数って言っても、内部的には2進数で表現しているわけです
で、2進数の小数って要は2^-1 + 2^-2 + ……って感じなわけ
ということは、10進数では1/9が無限小数になるように、2進数では10進数の0.1が無限小数になる

そして、表現できないってことはどっかで妥協する必要がある
この妥協が原因で計算結果に誤差が生じる

ということで、プログラムで実際に調べてみる
コンパイラはgcc(mingw64)

/**実行結果*********************************************/
C:\Users\owne>a.exe
80 * 80 * 0.01f: flt = 64.000000, bin = 42800000
0.01f * 80 * 80 : flt = 63.999996, bin = 427fffff
80 * 0.01f : flt = 0.800000, bin = 3f4ccccc
80 / 100.f : flt = 0.800000, bin = 3f4ccccd
/******************************************************/

"* 0.01"と"/ 100"でも差がありますね
printf使ってるんで、既定の実引数拡張でfloatからdouble型に型変換されてるけど、気にしない
誤差が出てるのは確かなので

初めはVC2012使ってたけど、%xが狂うんだよ……
なんで狂うんだろうね
誰か教えて……


#ifndef TEST
#define TEST
#include

unsigned int dump_4byte_le(const unsigned char *a_bin)
{
return ((((unsigned int)a_bin[3]) & 0xFF) << 24) + ((((unsigned int)a_bin[2]) & 0xFF) << 16)
+ ((((unsigned int)a_bin[1]) & 0xFF) << 8) + (((unsigned int)a_bin[0]) & 0xFF);
}
int main()
{
const float a = (float)(80 * 80 * 0.01f);
const float b = (float)(0.01f * 80 * 80);
const float c = (float)(80 * 0.01f);
const float d = (float)(80 / 100.f);
unsigned int ret;
ret = dump_4byte_le((unsigned char*)&a);
printf("80 * 80 * 0.01f: flt = %10f, bin = %08x\n", a, ret);
ret = dump_4byte_le((unsigned char*)&b);
printf("0.01f * 80 * 80 : flt = %10f, bin = %08x\n", b, ret);
ret = dump_4byte_le((unsigned char*)&c);
printf("80 * 0.01f : flt = %10f, bin = %08x\n", c, ret);
ret = dump_4byte_le((unsigned char*)&d);
printf("80 / 100.f : flt = %10f, bin = %08x\n", d, ret);
return 1;
}

#endif /* TEST */

コメントの投稿

非公開コメント

プロフィール

Author:drab
霊夢改変キャラ
「12 3 ! {V} [_]」
公開中
L霊夢でもl_reimuでも好きなように読んでください

最新記事
最新コメント
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク