floatだと正しい結果が得られない・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
Preston

floatだと正しい結果が得られない・・・

#1

投稿記事 by Preston » 11年前

はじめまして。
初めて1週間程度の超初心者です。 
本題ですが、下のコードを試しても正しい答えが出ません。1となるはずなのですが、0.250000と答えが返されます。
なお、powの「-8,8」のところを「-5,5」など異なる数字に変えると正しい答えが返ってきているようです。
また、floatをdoubleにすると「-8,8」でも正しい結果が返ってきます。
Windows7を使用しております。コンパイラなどの知識がほとんどないのですが、EasyIDECというソフトを使用しております。
よろしくお願いいたします。

コード:

#include <stdio.h>
#include <math.h>

int main(void){

float a = 0;
float b = pow(10.0, -8);
int m = pow(10.0, 8);
int n;

for(n=0; n<m; n++){
	a += b;
}

printf("%f\n", a);

return 0;
}

かずま

Re: floatだと正しい結果が得られない・・・

#2

投稿記事 by かずま » 11年前

0.00000001 を 100000000回足すと 1.0 になるのですが、
float は精度が 2進で23ビット、10進で 7桁弱しかありません。
実際は 2進で説明しないといけないのですが、
大雑把な説明でよければ 10進でできます。

コード:

  0.2500000
+ 0.000000010000000
--------------------
  0.250000010000000
精度が 7桁なので 0.2500000 に丸められます。
以下、これが繰り返されます。

かずま

Re: floatだと正しい結果が得られない・・・

#3

投稿記事 by かずま » 11年前

かずま さんが書きました:float は精度が 2進で23ビット、10進で 7桁弱しかありません。
すみません。訂正です。
float の精度は、2進24ビット、10進7桁ちょっとでした。

コード:

#include <stdio.h>
#include <math.h>
 
int main(void)
{
    float a = 0;
    float b = pow(10.0, -8);
    int m = pow(10.0, 8);
    int n;
    double a2 = 0;
    double b2 = pow(10.0, -8);
     
    for (n = 0; n < m; n++) {
        a += b;
        a2 += b2;
        if (n < 50 || n >= 22803397 && n <= 22803400 || n == m-1) {
            printf("%9d  %.24f  %.7a\n", n+1, a, a);
         // printf("%9s  %.24f  %.16a\n", "", a2, a2);
        }
    }
    return 0;
}
実行結果

コード:

        1  0.000000009999999939225290  0x1.5798ee0p-27
        2  0.000000019999999878450581  0x1.5798ee0p-26
        3  0.000000029999998929497451  0x1.01b2b20p-25
        4  0.000000039999999756901161  0x1.5798ee0p-25
        5  0.000000050000000584304871  0x1.ad7f2a0p-25
        6  0.000000059999997858994902  0x1.01b2b20p-24
        7  0.000000069999998686398612  0x1.2ca5d00p-24
        8  0.000000079999999513802322  0x1.5798ee0p-24
        9  0.000000090000000341206032  0x1.828c0c0p-24
       10  0.000000100000001168609740  0x1.ad7f2a0p-24
       11  0.000000110000001996013450  0x1.d872480p-24
       12  0.000000119999995717989800  0x1.01b2b20p-23
       13  0.000000129999989439966160  0x1.172c400p-23
       14  0.000000139999983161942510  0x1.2ca5ce0p-23
       15  0.000000149999976883918860  0x1.421f5c0p-23
       16  0.000000159999970605895210  0x1.5798ea0p-23
       17  0.000000169999964327871570  0x1.6d12780p-23
       18  0.000000179999958049847920  0x1.828c060p-23
       19  0.000000189999951771824270  0x1.9805940p-23
       20  0.000000199999945493800620  0x1.ad7f220p-23
       21  0.000000209999939215776980  0x1.c2f8b00p-23
       22  0.000000219999932937753330  0x1.d8723e0p-23
       23  0.000000229999926659729680  0x1.edebcc0p-23
       24  0.000000239999934592560750  0x1.01b2ae0p-22
       25  0.000000249999942525391820  0x1.0c6f760p-22
       26  0.000000259999950458222880  0x1.172c3e0p-22
       27  0.000000269999958391053950  0x1.21e9060p-22
       28  0.000000279999966323885020  0x1.2ca5ce0p-22
       29  0.000000289999974256716090  0x1.3762960p-22
       30  0.000000299999982189547150  0x1.421f5e0p-22
       31  0.000000309999990122378220  0x1.4cdc260p-22
       32  0.000000319999998055209290  0x1.5798ee0p-22
       33  0.000000330000005988040360  0x1.6255b60p-22
       34  0.000000340000013920871420  0x1.6d127e0p-22
       35  0.000000350000021853702490  0x1.77cf460p-22
       36  0.000000360000029786533560  0x1.828c0e0p-22
       37  0.000000370000037719364630  0x1.8d48d60p-22
       38  0.000000380000045652195690  0x1.98059e0p-22
       39  0.000000390000053585026760  0x1.a2c2660p-22
       40  0.000000400000061517857830  0x1.ad7f2e0p-22
       41  0.000000410000069450688900  0x1.b83bf60p-22
       42  0.000000420000077383519970  0x1.c2f8be0p-22
       43  0.000000430000085316351030  0x1.cdb5860p-22
       44  0.000000440000093249182100  0x1.d8724e0p-22
       45  0.000000450000101182013170  0x1.e32f160p-22
       46  0.000000460000109114844240  0x1.edebde0p-22
       47  0.000000470000117047675300  0x1.f8a8a60p-22
       48  0.000000480000096558796940  0x1.01b2b60p-21
       49  0.000000490000104491628010  0x1.07111a0p-21
       50  0.000000500000112424459080  0x1.0c6f7e0p-21
 22803398  0.249999970197677610000000  0x1.fffffc0p-3
 22803399  0.249999985098838810000000  0x1.fffffe0p-3
 22803400  0.250000000000000000000000  0x1.0000000p-2
 22803401  0.250000000000000000000000  0x1.0000000p-2
100000000  0.250000000000000000000000  0x1.0000000p-2
pow(10, -8) = 0.00000001
float だと 0.000000009999999939225290、16進で 0x1.5798ee0p-27
2進で 1.0101 0111 1001 1000 1100 110 p-27
すなわち、0.00000000000000000000000000101010111100110001100110

22803399個足すと 0.249999985098838810000000、16進で 0x1.fffffe0p-3
2進で、1.1111 1111 1111 1111 1111 111 p-3
すなわち、0.00111111111111111111111111

これらを足すと

コード:

  0.00111111111111111111111111
+ 0.00000000000000000000000000101010111100110001100110
--------------------------------------------------------
  0.00111111111111111111111111101010111100110001100110
      ↓ 1が 25ビットあって、切り上げると、
  0.0100000000000000000000000
次に

コード:

  0.0100000000000000000000000
+ 0.00000000000000000000000000101010111100110001100110
--------------------------------------------------------
  0.01000000000000000000000000101010111100110001100110
      ↓  24ビットなので、切り捨て
  0.0100000000000000000000000

閉鎖

“C言語何でも質問掲示板” へ戻る