C言語関係掲示板

過去ログ

No.1007 実数の誤差について

[戻る] [ホームページ]
No.993

実数の誤差について
投稿者---Takako_T(2004/01/15 13:16:00)


はじめまして。

 過去掲示板(No45など)で、誤差について扱われていましたが、
分かりづらいところがあるので、質問します。

 丸め誤差、打切り誤差のほかに色々な誤差があることも分かりました。
ですが、繰り返しの計算回数を変えたときに誤差がマイナスのほうから
プラスのほうに変わってしまう理由が分かりません。

/* ある実数を100回足した結果と1000足した結果 */
#include <stdio.h>
#define I 100
#define J 1000
int main(void)
{
    int i;
    float s,t,x;
    s = 0.0;
    t = 0.0;
    puts("実数を入力してから、CTRL+Zを押してください。");
    scanf("%f\n", &x);
    
    for (i = 1; i <= I; i++){
        t = t + x;
                }
    for (i = 1; i <= J; i++){
        s = s + x;        
                                }
    printf("%gを%d回足すと%fです。\n",x,I,t);
    printf("%gを%d回足すと%fです。\n",x,J,s);
    
    return (0);
}


 まず、値に0.01を使いました。2進数にしたときに、無限小数となり
有限長では表現できないために誤差はおきます。ですから100回足し算を
繰り返すと0.999999になるのは何となく分かります。途中で打ち切って
(丸めて)表現するのだから、少なくなるのだろうな...と。ですが、
1000回足すと10.000134となり、正しい値から増えるのが分かりません。
なぜこの場合は増えるのでしょうか? また、入力する値が0.1のときは
100回のときに増えて、1000回のときには減っています。

 使用しているCコンパイラはLSIC86試食版です。よろしくお願いします。

No.997

Re:実数の誤差について
投稿者---かずま(2004/01/15 15:14:52)


0.01 を 2進で表すと、
1.0100 0111 1010 1110 0001 0100 0111 1010 1110 0001 ... x 2-7
float は、24ビットしか保持できないので、
1.0100 0111 1010 1110 0001 010 x 2-7
これは、0.01 の真の値よりは小さい。
だから、100回足しても 1 より大きくなることはないと思うでしょう。

ところが、和がだんだん大きくなったとき、その和と 0.01 との間に桁のずれ
が生じます。たとえば、10.00 + 0.01 を 2 進で計算すると、
   1010.0000 0000 0000 0000 0000
+     0.0000 0010 1000 1111 0101 1100 0010 10
-----------------------------------------------------
   1010.0000 0010 1000 1111 0101 1100 0010 10

float は 24ビットしか保持できないので、丸めて(この場合切り上げ)、
   1010.0000 0010 1000 1111 0110
1.0100 0111 1010 1110 0001 010 x 2-7 を足したつもりなのに、
1.0100 0111 1011 0000 0000 000 x 2-7 を足したことになります。
これは、0.01 の真の値よりかなり大きな値です。

このように、足すべき 0.01 の下位の桁が落とされるときの丸めが、切捨てだっ
たり、切り上げだったりすることによって、真の値より小さい値が足されたり、
大きい値が足されたりするのです。

No.1014

Re:実数の誤差について
投稿者---Takako_T(2004/01/16 23:30:25)


かずま 様

 返事が遅れて失礼しました。なぜ減ったり増えたりするのかが
よく分かりました。ありがとうございました。これからも
がんばって勉強します。