• ベストアンサー

float型での計算での質問

下記コードについて、1から10までの値を0.1刻みで順に表示するプログラムですが、結果がこのようになりません。 表示結果 2.700000 までは0.1刻みなのですが、2.800000 と表示されるはずが 2.799999 となってしまいます。 コンパイラーは Borland C++ 5.5.1 for Win32 です。 なぜこのようになるのか教えてください。 int main(void) { float f; for(f=1; f<10.1; f=f + 0.1) printf("%f\n",f); return 0; }

質問者が選んだベストアンサー

  • ベストアンサー
  • chie65536
  • ベストアンサー率41% (2512/6032)
回答No.3

0.1を2進数にすると無限小数になりますが、値は有限な領域に格納されます。 つまり、2進数にした瞬間に、ある程度の所で切り捨てられてしまいます。 切り捨てた誤差は「足し算を続ける」事によって累積されて溜まって行きます。 そして、溜まった誤差は、28回繰り返した時点で0.000001を超え、値を表示した時に読める形で表面化します。 ・0.1を2進数にすると無限小数になる理由 2進数での小数は、(1/2)*a+(1/4)*b+(1/8)*c+…と言う形で表されます。 つまり、2のn乗分の1「1/(2^n)」の集まりで表現します。 例えば、0.8125は、 0.8125=(1/2^1)+(1/2^2)+(1/2^4) =(1/2)+(1/4)+(1/16) =0.5+0.25+0.0625 で表現されます。 2進と10進で書けば 0.1(2)=0.5 0.01(2)=0.25 0.0001(2)=0.0625 なので、0.1101(2)が0.8125の2進表現になります。 で、0.1はと言うと 0.1=0.0625+0.0375 =0.0625+0.03125+0.00625 =0.0625+0.03125+0.00390625+0.00234375 =0.0625+0.03125+0.00390625+0.001953125+0.000390625 と言う感じで、どこまで行ってもピッタリと終りません。 2進数で0.1を書くと 0.00011001100110011… となり「0011」が繰り返しているのが判りますね。 つまり「0.1を2進数にすると無限小数になる」訳です。 これは、以下のように電卓で簡単に試せるので、やってみましょう。 1.電卓に「0.1」を入れる 2.「**2」と押す 3.「=」を押して2倍する。 4.続けて「=」を押して2倍する。 こうすると、小数点の部分が「.2」「.4」「.8」「.6」で繰り返します。 2進数は2倍すると1桁右にずれるので「2倍すると、10進数表現で小数部に同じ数時が循環して出て来る」と言うことはつまり「2進数表現で小数部に同じビットパターンが繰り返している」って事で「2進数表現で循環小数」だと判ります。

type0000
質問者

お礼

ありがとうございました よく分かりました 勉強になりました

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (5)

  • chirubou
  • ベストアンサー率37% (189/502)
回答No.6

No.5 です。すいません、書きかけでした。 例えば、以下のようなプログラムで、 int main(void) { float a, x, y; int i; a = 1.0; x = 0.0; for( i=0; i<10; i++ ) { x += a; a /= 10.0; } a = 1.0e-9; y = 0.0; for( i=0; i<10; i++ ) { y += a; a *= 10.0; } printf("x=%f?n", x ); printf("y=%f?n", y ); if( x != y ) printf( "not same !!!?n" ); } 私の環境だと、 x=1.111111 y=1.111111 not same !!! となります。

全文を見る
すると、全ての回答が全文表示されます。
  • chirubou
  • ベストアンサー率37% (189/502)
回答No.5

理由は他の回答者さんの通りですが、ひとつ関連してアドバイスさせてください。初心者がはまり易いと思いますので。 つまりは、実数(float, double)は内部的に近似した値として表現されてることが原因です。このため、2つの実数が同じであることを == で比較すること、例えば、 失敗する可能性が高いので、やらないように注意してください。

全文を見る
すると、全ての回答が全文表示されます。
  • driverII
  • ベストアンサー率27% (248/913)
回答No.4

先日、Excel VBA で作ったソフトで同様な事が起きました。 その時、調べたページを挙げておきます。(わかりやすい解説があるので) 誤差対策すれば大丈夫ですよ。

参考URL:
http://pc.nikkeibp.co.jp/pc21/special/gosa/index.shtml
全文を見る
すると、全ての回答が全文表示されます。
  • galluda
  • ベストアンサー率35% (440/1242)
回答No.2

がると申します。 float(doubleもそうですが)は、#1さんも書かれている通り、飽く迄「近似値」であって、正確な数値は出てきません。 基本的にプログラムで「小数点を含む計算をする」のは割合にご法度なので。 上述のような処理であれば「素直に10倍して整数であつかう」のが通例です。 ちなみに「どうしても小数点以下を、しかも厳密な値で計算したい」場合、そういう用途用の専用ライブラリを別途購入する必要があります。

全文を見る
すると、全ての回答が全文表示されます。
  • Trick--o--
  • ベストアンサー率20% (413/2034)
回答No.1

PCの内部では、2進数で計算しています。 実は、10進数の0.1を2進数にすると無限小数になってしまうのです。 しかし、データとして無限小数をそのまま持つことはできませんから、どうしても誤差が出てしまいます。 そのため、計算に狂いが出るのです。 http://ja.wikipedia.org/wiki/%E8%AA%A4%E5%B7%AE#.E8.A8.88.E7.AE.97.E8.AA.A4.E5.B7.AE.E3.81.AE.E7.A8.AE.E9.A1.9E

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 計算に誤差が出る?

    0.1 + 0.2 + 0.3・・・・・・ このように行うプログラムを2通りに分けて処理をして見ました。 以下にソースを載せます。 #include <stdio.h> int main() { float sum, i; float sum2; int f; for(i=0.1, sum=0.0; i<=100.0; sum+=(float)i, i+=0.1); printf("%f\n", sum); for(f=1, sum2=0.0; f<=1000; sum2+=(float)f/10.0, f++); printf("%f\n", sum2); return 0; } 初めのfor文と2番目のfor文では同じ処理を行っているのですが、計算結果が微妙に異なって出力されてしまいました。 理由が分かる方は教えてもらえないでしょうか?

  • C言語の実数型の足し算

    C言語初心者です。関数の勉強していて、実数型計算に出くわしました。 #include <stdio.h> float add(float a, float b) { return a+b; } int main(void) { float x=10.5,y=20.3; printf("%f %f\n",x,y); printf("%f\n",add(x,y)); return 0; } としたら、 10.500000 20.299999 30.799999 という結果になりました。今のところint型でずーっと勉強していたので、20.3の20.299999表記が怪しく感じられ、結果も同様に怪しく感じられます。どうして、10.5+20.3=30.8とすっっきり表示してくれないのでしょうか。

  • float型関数で定義するプログラミング

    今プログラミングを行っているのですが、Xn+1=Xn-f(Xn)/g(Xn)(f(x)=x*x-x-1,g(x)=2x-1,これらはfloat型の関数とすること)で初期値Xo=-2としたときに繰り返しxを求めていき、|f(x)|=<10^-5となるまで計算するプログラムを作成したいのですが結果がおかしくなるので、ここからどう手直しすればいいのかわかりません。 #include<stdio.h> float wa(void); int main(void) { float a,i; for (i = -2; i <= 0.00005; i++) { a = wa(); printf("%f\n", a); } return 0; } float wa(void) { float l = 0, i, m, n, x,b; for (i = -2; i <= 0.00005; i++) { x = i; l *= i; m = x*x - x - 1; n = (2 * x) - 1; b = l - (m / n); } return b; } 結果 -1.000000 -1.000000 -1.000000 正直言ってどういう結果になればいいのかもわかりません。 せめてどういうような結果になるのかだけでも教えていただければありがたいです。

  • 長方形、円、三角形の計算するプログラムでエラーがでます

    タイトルの通りなんですがエラーがでます>< コンパイラはできたのですが、実行して二つ目の入力するとこで、入力したあと止まります。 どこがおかしいのでしょうか? #include <stdio.h> int sikaku(void); int en(void); int main(void) { char ch; int a,b; printf("円(A) 長方形(B) 三角形(C)\n"); printf("入力してください:"); ch = getche(); if(ch == 'C'){ printf("\n底辺を入力してください:"); scanf("%d ",a); printf("高さを入力してください:\n"); scanf("%d",b); printf("%dです",a * b); } else if(ch == 'B') sikaku(); else if(ch == 'A') en(); return 0; } int en(void) { int a; float f; printf("\n半径を入力してください:"); scanf("%d",a); printf("円周率を入力してください:"); scanf("%f",f); printf("%fです",a * a * f); return 0; } int sikaku(void) { int a,b; printf("\n縦を入力してください:"); scanf("%d",a); printf("横を入力してくさい:\n"); scanf("%d",b); printf("dです",a * b); return 0; }

  • C言語のfloat型変数の値代入と表示について

    float型変数の値代入と表示について質問があります。 #include <stdio.h> int main(void) {  float flVal = 50.456;  printf("float型変数:%f", flVal);  return 0; } 上記を実行すると、「float型変数:50.456001」と表示されました。 また、float flVal = 50.1; と変えて実行すると、「float型変数:50.099998」と表示されました。 それぞれ期待していた結果は、 「float型変数:50.456000」、「float型変数:50.100000」だったのですが 代入した値と結果が微妙に異なる理由は何でしょうか。よろしくお願いします。

  • 行列の計算

    #include<stdio.h> #define N 2 #define M 3 void hyoji(float[][M]); int main(){ int i,j,k; float a[N][M] = {{2.0,2.0,2.0},{2.0,2.0,2.0}}; float b[M][M] = {{1.0,1.0,1.0},{2.0,2.0,2.0},{1.0,1.0,1.0}}; float c[N][N]; for(i=0; i<N; i++){ for(j=0; j<M; j++){ c[i][j] = 0; for(k=0; k<M; k++){ c[i][j] += a[i][k] * b[k][j]; } } } hyoji(c); return(0); } void hyoji(float x[][M]){ int i,j; for(i=0; i<N; i++){ for(j=0; j<M; j++){ printf("%4.1f ",x[i][j]); } printf("\n"); } } 以上のプログラムで 行列aと行列bをかけ合せた行列cを求めるのですが コンパイルすると 8 8 8 8 8 1 となり、正しい結果がでません。 なにが間違っているのでしょうか?? よろしくお願いします。

  • windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでた

    windowsのコンパイラーで正しく実行されたのに、gccのコンパイラーでエラーがでたソースコードです。ファィル名test.c です。Linux(Red Hat9) gccです。windowsのコンパイラーはCPad for Borland C++Compilerです。 #include <stdio.h> void main() //intからvoidに変更した { int i, j; for (i=1; i<=9; i++){ printf("%2d ",i); //%2dで、iが2桁に表示 } printf("\n"); printf("***************************\n"); //この罫線もどきの書き方はダサいので工夫してください for (i = 1; i<=9; i++){ for (j = 1; j<= 9; j++) { printf("%2d ", i*j); if (j == 9) printf("\n"); //1行表示後改行 } } return; //voidにしたので0を取った! } これがLinux(RedHat9)gccでは以下のエラーが出ます。 (test.c: 関数 `main' 内: test.c:4: 警告: `main' の戻り値の型が `int' ではありません)  なぜ、同じソースコードでエラーが起こるのですか?  Linux gccでは、この場合`int' 以外の何が必要なのでしょうか? 以上よろしくお願いします。

  • doubleとfloatについて

    #include <stdio.h> int main() { float height,weight; printf("身長と体重を入力してください。\n"); scanf("%f",&height); scanf("%f",&weight); printf("身長は%fセンチ:体重は%fキロです。\n",height,weight); return 0; } 上記のようなプログラムを作って、身長には175.1体重には56.1という入力を行なって実行したところ、 身長は175.100006センチ:体重は56.099998キロです。 という結果が返ってきました。 heightとweightをdouble型で宣言したところ(もちろんscanf文の変換仕様は%lfにしています。)、結果は 身長は175.100000センチ:体重は56.100000キロです。 と私が、期待していたものが返ってきました。なぜfloat型だと期待通りの結果が返ってこないのでしょうか?ご教授お願い致します。

  • float型関数の定義の仕方がわかりません。

    次のプログラミングでfloat型関数を定義しようとしても下の矢印のところにどんな文字を入れても「初期化されてないローカル変数が使用されます。」と出て、どうしてもうまくいきません。 こういう場合どこを直せばエラーが出なくなるのでしょうか? #include<stdio.h> float wa(float  );       ↑ int main(void) { float a; a = wa();      ↑ printf("%f\n",a); return 0; } float wa(float  )       ↑ { float l = 0, i, m, n, x,b; for (i = -2; i <= 0.00005; i++) { x = i; l *= i; m = x*x - x - 1; n = (2 * x) - 1; b = l - (m / n); } return b; }

  • C++の打切り誤差についてお聞きしたいのですが・・

    ↓のプログラムが、なぜ実行結果のsumが1ではなく1.000054や9.99999999999906e-001、9.9999999999990619e-001といった答えにになってしまうのでしょうか? 10000のところを512でやった場合は普通に1と出力されたのに・・・ #include <stdio.h> int main(void){ int i; float f; double d; f = 0.0; for(i = 0; i<10000; i++) { f += 1.0/10000; } printf("float: n=%d sum=%f\n", 10000, f); d = 0.0; for(i = 0; i<10000; i++) { d += 1.0/10000; }// end for printf("double:16.14e: n=%d sum=%16.14e\n", 10000, d); printf("double:18.16e: n=%d sum=%18.16e\n", 10000, d); return 0; } 実行結果 float: n=10000 sum=1.000054 double:16.14e: n=10000 sum=9.99999999999906e-001 double:18.16e: n=10000 sum=9.9999999999990619e-001 続行するには何かキーを押してください . . .

mr-icd102 パソコンが認識しない
このQ&Aのポイント
  • mr-icd102 パソコンが認識しないについての質問です。ノートパソコンの利用状況や問題の詳細について記載しています。
  • 1年前はetax申請ができたが、最近パソコンがデバイスを認識しない状態です。ドライバの再インストールとWindows 11の利用状況についても説明しています。
  • エレコム株式会社の製品に関連しており、mr-icd102というパソコンが認識しない問題について質問しています。
回答を見る