• ベストアンサー

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