質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.46%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

2回答

1147閲覧

C言語で小数を用いた足し算と掛け算の時の誤差を減らしたい。

jonko

総合スコア15

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2021/10/10 16:53

例として、1から5まで0.1刻みの値の総和と積を出力するプログラムを考えます。大した誤差は無いと思いますが、誤差を最小限に抑えるプログラムを考えてみました。和については該当の値の10倍にあたる整数値を足していき、最後に0.1をかけています。積については該当の値の10のn乗を考えて最後に10のn乗で割るイメージです。
方針として私はこれで誤差を最小に抑えられると思ったのですが、他にもより良い方法があれば教えていただけますでしょうか。もしくはこれで誤差を最小に抑えられるのであれば、これで大丈夫といったコメントを頂けると幸いです。

C

1#include <stdio.h> 2 3int main(void){ 4 int sum=0; 5 unsigned long long int product=1, count=1; 6 for (int i = 10; i <= 50; i++) { 7 count *= 10; 8 sum += i; 9 product *= i; 10 printf("%d : sum = %-3.1f, product = %-8.3f\n",i-1,sum*0.1,(float) product/count); 11 } 12}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

なぜ誤差のある計算方法がデフォルトなのか、それはメモリや計算時間等が制限となりうるからです。
誤差はあるけれど、現実的な計算としては十分だろう、ということで現在の浮動小数点型の演算が実用になっています。もし、精度が足りないのであれば、精度を上げる代償を支払わなければいけません。

より良い方法

それを論ずるためには、計算される値にどのような制限をかけられるのか、どのくらいの誤差が許されるのか、それらに対してどのくらいの支払いができるのかの評価軸が必要ですので呈示してください(計算される値と計算は呈示されていますが)。「良い」はそれらのバランスの評価の問題です。
普通に処理系で提供される浮動小数点型の誤差が受け入れられるものであれば「特別なことはしない」のが最良の方法かも知れません。

投稿2021/10/10 22:35

編集2021/10/10 22:59
thkana

総合スコア7659

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jonko

2021/10/11 03:01

ご指摘いただきありがとうございます。誤差を減らすと計算時間やメモリを犠牲にしてしまうのですね。これからは誤差の許容範囲と計算時間のバランスを考えて行きたいと思います。回答ありがとうございました。
guest

0

ベストアンサー

考え方としてはOKで、和については改善点は無いです。

積については、unsigned long long intでもオーバーフローするので駄目です。
productcountは、doubleにする必要があります。ただし、これでも有効桁数が足りないので、正確には計算できません。ちょっと計算してみると10進48桁になり、正確な計算のためには仮数部が160bit必要なので4倍精度でも足りません。なので、正確な計算には、多倍長10進計算ライブラリが必要です。タイトルにある「誤差を減らしたい」というだけであれば、doubleか、あればlong doubleを使うといいです。

投稿2021/10/10 18:51

編集2021/10/10 18:57
otn

総合スコア84804

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

fana

2021/10/11 02:17

データを分子と分母で持っている形なので ループ中に適宜約分してやればオーバーフローに対抗できないだろうか? …とか思いました.
jonko

2021/10/11 02:58

回答ありがとうございます。オーバーフローは確かに起こっているかと思います。基本的な方針はあっているかと思ったのでオーバーフローに注意して考えたいと思います。 場合によってはfanaさんの様に適宜約分するのが現実的かと思いましたが、多倍長10進数計算ライブラリなるものがあるのですね。奥が深そうで興味深いです。調べてみようと思います。
otn

2021/10/11 04:27

他の回答にあるコスト対効果も考えると、今回の「10倍する」は微少コストなのでどんどんやればいいですが、約分(分母の素因数が2と5だけなのでそれほどの効果はなさそうですが)や、多倍長10進計算ライブラリの採用は、完全な正確性が求められる時ということになるかと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.46%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問