• ベストアンサー

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とすっっきり表示してくれないのでしょうか。

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

  • ベストアンサー
  • yama1718
  • ベストアンサー率41% (670/1618)
回答No.4

二進数はわかりますよね、桁が増える毎に倍の値になります。 1 → 1 2 → 10 3 → 11 4 → 100 それで、二進数には少数もあるのです、割り切れる値で言うと、 桁が下に増える毎に半分の値になります。 0.5 → 0.1 0.25 → 0.01 0.125 → 0.001 その二進数では 0.1 ですら割り切れない近似値になってしまいます。 0.1 → 0.00011001100110011001100… → 0.099999904632568359375… なぜ、この様に誤差が出るのに少数を二進数で計算しているかは、 速度を優先して演算プロセッサがその様に計算する仕様になっているからです。 金融計算では小数点以下の誤差も問題になりますから別に通貨型と呼ばれる。 内部では値を100倍とか10000倍などにして扱う固定小数点型を使用します。 他にはBCD演算と言って元から10進数で計算する方法もありますが、 計算速度がかなり遅いのであまり使用されていません。 CやC++でもBCD演算ライブラリを使用すれば誤差の少ない計算ができます。 (確かBorland C++ のオプションにBCD演算のライブラリがあったかな)

参考URL:
http://www.cc.kyoto-su.ac.jp/~yamada/pB/float.html
inocchi210
質問者

お礼

速度とプロセッサの関係、固定小数点やBCD演算と、本来ならC言語の勉強をする前にしておかなければならなかったのですね・・・実務的なお話とても参考になりました、ありがとうございました。

その他の回答 (5)

  • tadys
  • ベストアンサー率40% (856/2135)
回答No.6

コンピュータの中での計算は2進数で行っていますが 2進数で3/10を計算すると循環小数になってしまいます。 しかしながら、コンピュータで扱える数値の桁は有限なので 無限に続く数値を正確に表す事はできません。 0.3=3/10を2進数を用いて筆算の方法で計算してみると 11/1010   2進数 1回目       0.01      _______ 1010/11.00      10 10     ――――――――         10 2回目       0.01001      ________ 1010/11.00      10 10     ――――――――         10000          1010     ―――――――――           110 となって、途中で11(10進数の3)が再び現れるので循環小数になります。 10進数で1/3=0.33333・・・・・ となる計算も 3進数で計算すれば 1/10 = 0.1 となって有限の小数になります。

inocchi210
質問者

お礼

筆算の丁寧な記述、どうもありがとうございました。今度からプログラムを勉強するときは、コンピュータ内部で2進計算されているんだということを意識してしようと思いました。循環小数は3進数との関係も、今後勉強していきたいと思います、ありがとうございました。

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.5

二進数と十進数の変換時に生じる誤差のこともありますが、元々有効桁数が小数点以下1桁しかないのだから、小数点以下1桁までしか意味をなさないのは当然です。 printf("%.1f %.1f\n",x,y); printf("%.1f\n",add(x,y)); と書けばよいのではないでしょうか? ちなみに、C言語における「実数型」というのは、虚数型(_Complexや_Imaginary)に対しての実数型ですので、整数型も含みます。

inocchi210
質問者

お礼

誤差、有効桁、実数型や虚数型があることを理解できました、ありがとうございました。

  • asuncion
  • ベストアンサー率33% (2127/6289)
回答No.3

浮動小数点数のうち、2のべき乗の和の形で表わせない数値(例えば今回の20.3)を 有限のバイト数で表現しようとするとき、必ず誤差を伴います。 厳密な数値である20.3が、コンピューターの中でも厳密に20.3である、 という保証はどこにもありません。

inocchi210
質問者

お礼

20.3がコンピュータ内部ですっきりした20.3でないというのは少し驚きましたが、浮動小数点や誤差の話とCのプログラムのつながりがわかりましたので、ありがとうございました。

  • Tasuke22
  • ベストアンサー率33% (1799/5383)
回答No.2

結論を先に書けば、実数型では0.3が無いからです。 常に概数の表現であることを踏まえなければなりません。

参考URL:
http://ja.wikipedia.org/wiki/%E5%AE%9F%E6%95%B0%E5%9E%8B
inocchi210
質問者

お礼

コンピュータ内部が概算であることに気がつきました、確かに、無限の数字を有限にするということを今度から考えてプログラミングの勉強をしたいと思います。ありがとうございました。

  • notnot
  • ベストアンサー率47% (4900/10358)
回答No.1

実数は内部で十進数でなく二進数で保持されていることはご存じでしょうか? 0.3 や 0.1 は二進数では循環小数になるので、有限桁では正確に表現できません。0.5 とか 0.25 0.75 0.125 などは正確に表現できます。 他の例では例えば、1/3 は十進数だと循環小数ですが、三進数だと小数点以下一桁です。

inocchi210
質問者

お礼

r進数の勉強は苦手だったので、参考程度に読み飛ばしてC言語教科書を読んでいました。コンピュータ内部での実数が2進法との兼ね合いで、Cのプログラムの結果にまで出てくるとは少し驚きでした。参考になりました、ありがとうございました。