c
1#include <stdio.h> 2int main(void){ 3 float b =0; 4 for(int i=0;i<10000;i++){ 5 b+=0.01; 6 } 7 printf("%f",b); 8}
0.01を10000回足すだけのプログラムですが、
結果は100.002953 になります。
float計算する際の誤差を最小限に抑える方法を教えてください。
たとえば数値が0.01刻みと分かっているなら100倍してintで計算して最後に100で割ればよいかなと思っていたのですが、
C
1#include <stdio.h> 2int main(void){ 3 float b =9.44; 4 int c=b*100; 5 printf("%d",c); 6}
これの結果が9.43なんです。
9.44を100倍にした時点で9.43となるのでお手上げです。
どうすれば方法が使われているでしょうか。教えてください。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

回答6件
0
9.44を100倍にした時点で9.43となるのでお手上げです。
それ以前です。9.44という値自体を保持できないのですから。
Microsoft C(Visual Studio)で試してみると、
float b =9.44;
で格納した時点で変数に入っているのは0x3d0a1741, 9.43999958038330078125だったりするのです。
しかも、この誤差がマイナス方向という決まりはなく、例えば
b=9.43;
とすれば、格納されていたのは0x48e11641, 9.43000030517578125 でした。
2進数で表現しきれない「誤差」をどのように処理するかは別にC言語の規格レベルで決められている話でもなく(そもそも変数の内部表現も規定されていない処理系依存)、となると一般的に「誤差の影響をいかに少なくするか」というお題で話せるのは「演算を整数の範囲に収める」ぐらいしか無いというのは当然の流れではないでしょうか。
どのように質問を変えましょう...「既存のMicrosoftのCやgccで、float型を使って、小数の範囲の値を誤差なく(あるいは一般的に誤差を少なくするように)扱いたい」という制限をつけたなら、「無理」ということしか言えなくなります。
floatにこだわらないなら誤差を少なくするならdoubleを使うし、処理系をいじっていいなら浮動小数点型の内部処理が10進表現のC言語処理系を開発する、という手段は無いとはいえませんが。
C#だとdecimal型なんてありますね。
投稿2020/05/31 23:25
編集2020/05/31 23:36総合スコア7723
0
float計算する際の誤差を最小限に抑える方法
そもそもとして、float型は2進数-10進数の変換誤差がある型であるため、常に有効数字を
意識して計算し、適切な位置で四捨五入しながら使うのが前提となっている型です。よって、
あなたがやっているように、有効数字の桁数によるまるめを行わないでおいて誤差を語ることには
何の意味もありません。
なぜなら、この「数値のまるめを計算のどこでどのように行うべきか」が「floatで計算する
上で誤差を最小限に抑える方法」に直結しているからです。そして、有効数字でのまるめを
適切に行っているのであれば、あなたが誤差と言っているものはいずれも誤差になりません。
仮に、有効数字を意識した計算順がどうあるべきか、という話であるとしても、非常に条件付けが
多い話になるため、汎用的に語ることは難しくなります。このあたりを知らないのであれば、
指数部分を分離するなどして10進数のまま計算する(けど計算が遅い)型だけで計算するほうが、
誤差がほぼ出ずに済むのであなたの目的を満たしやすいと思われます。
投稿2020/06/01 01:38
総合スコア596
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
誤差がまずい場合は,まずは整数でできないかを考える…… という話は既出ですので……
0.01を10000回足す
というケースに当てはまるかどうか,私自身あやふやですが(間違ってれば鋭い突っ込みが入るハズなので,そちらを参照してください)
誤差を減らす方向の方策としては,
単純に「演算回数を減らす」という手が1つはあるかと.
float b = 0.01f * 10000;
なら1回の乗算で済むので,
10000回
というのが動的に決まる回数なのだとしても,とりあえず回数は整数でカウントしておき,必要な時点で0.01にその回数を乗じるというのはどうでしょうか.
不勉強なので,効果のほどを明確に述べることはできませんが,有理数を扱う:
「分子と分母を別々に整数で扱っておいて,本当にfloatとかdoubleでの値が必要になったときだけ,分子/分母
として値を作る」というやり方もたまに見かけるような気がします.
9.44を100倍して整数にする側の話は,
int c=b*100;
を
int c = ( b * 100 + 0.5f );
とでもしてやればどうでしょうか.(小数点以下を四捨五入)
投稿2020/06/01 01:24
編集2020/06/01 01:31総合スコア12151
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
ベストアンサー
float計算する際の誤差を最小限に抑える方法を教えてください。
という質問で、最初からfloatを使わなければいいという趣旨の回答が来るんですねこのサイト
これからは整数だけを扱っていこうとおもいます。ありがとうございました
微小な数を足して切り捨てる方法があることは把握していたので、
その微小な数って具体的にどう設定するの?みたいな話がしたかったなあ
これは質問の方法が悪かったと諦めます。こういうのってもう一度質問していいのかな。本文変えても目に触れないだろうしなあ
投稿2020/05/31 14:23

退会済みユーザー
総合スコア0
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。

退会済みユーザー
2020/05/31 14:35 編集
2020/05/31 14:48
2020/06/01 00:36
2020/06/01 00:51
2020/06/01 01:37
2020/06/01 04:03 編集

あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/06/01 00:24
2020/06/01 03:29 編集