こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

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

投稿日時 - 2009-12-10 21:35:57

QNo.5512983

暇なときに回答ください

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

二進数はわかりますよね、桁が増える毎に倍の値になります。
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

投稿日時 - 2009-12-10 23:10:02

お礼

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

投稿日時 - 2009-12-12 10:53:05

このQ&Aは役に立ちましたか?

6人が「このQ&Aが役に立った」と投票しています

回答(6)

ANo.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 となって有限の小数になります。

投稿日時 - 2009-12-11 09:16:08

お礼

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

投稿日時 - 2009-12-12 11:01:05

ANo.5

二進数と十進数の変換時に生じる誤差のこともありますが、元々有効桁数が小数点以下1桁しかないのだから、小数点以下1桁までしか意味をなさないのは当然です。

printf("%.1f %.1f\n",x,y);
printf("%.1f\n",add(x,y));

と書けばよいのではないでしょうか?

ちなみに、C言語における「実数型」というのは、虚数型(_Complexや_Imaginary)に対しての実数型ですので、整数型も含みます。

投稿日時 - 2009-12-10 23:19:17

お礼

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

投稿日時 - 2009-12-12 10:58:50

ANo.3

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

投稿日時 - 2009-12-10 22:59:55

お礼

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

投稿日時 - 2009-12-12 10:48:04

ANo.2

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

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

投稿日時 - 2009-12-10 22:08:30

お礼

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

投稿日時 - 2009-12-12 10:45:32

ANo.1

実数は内部で十進数でなく二進数で保持されていることはご存じでしょうか?
0.3 や 0.1 は二進数では循環小数になるので、有限桁では正確に表現できません。0.5 とか 0.25 0.75 0.125 などは正確に表現できます。

他の例では例えば、1/3 は十進数だと循環小数ですが、三進数だと小数点以下一桁です。

投稿日時 - 2009-12-10 21:55:24

お礼

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

投稿日時 - 2009-12-12 10:43:25

あなたにオススメの質問