みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

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

解決済みの質問

浮動小数演算での誤差の蓄積が起こっているのかどうか

C++でプログラミングの勉強をしています.
以下の現象で悩んでいます.

ある実数演算(double)をする関数A(実数パラメータxを用いた積算)を
以下の2種類の方法で用いると,結果が微妙に変わってしまいます.


(1)パラメータxを微小に変化させながら,関数Aをfor文でループさせ,最後の結果を入手する.
 (xを変化させても,Aの結果が変わらないようにその他の変数を初期化しているのですが・・・)

(2) (1)の最終条件(パラメータxの大きさ)を同じにして,関数Aを1回のみ用いて,結果を入手する.


条件は同じはずなので,同じ結果が出て欲しいのですが,
結果が変わってしまい困っています.
この場合考えられる原因としては何があるでしょうか?

・前のパラメータの時の実数演算の誤差が積み重なっている可能性はありますか?
(でも,ループ中に共有している変数は必ず初期化しているのですが・・・)


ソースコードは複雑なため,載せることはできません.
大変申し訳ございません.
原因としてどんなことが考えられるのかを教えて頂けると助かります.
宜しくお願い致します.

投稿日時 - 2011-09-17 20:04:24

QNo.7017391

困ってます

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

パラメータをたとえば0→1の間で10000分割した場合、
forループで1万回0.0001を加算して最後に1になった場合
の結果を出していれば、誤差で一致しない可能性があると思います。
0.0001×10000でも誤差が出るでしょう。

今思いついたのはその位です。

投稿日時 - 2011-09-17 20:28:54

補足

回答の通りかもしれません.

(1)はパラメータxを0.01刻みでループさせています.
例えば
「xを0.25まで加算させた際の結果」と
「xに0.25を代入した際の結果」では違う値になっている可能性があります.

それならば,ループの際に0.01加算するのではなく,
「x(整数型にしておく)に1加算して,100で割る」
という方法で対処できますか?
つまり,0.01ずつ加算して0.25を表現する(A式)のではなく,
B式でやれば誤差は生じないでしょうか?

A式:y(実数) = x(実数) + 0.01で
B式:y(実数) = ( x(整数) + 1 ) / 100

投稿日時 - 2011-09-17 21:19:07

お礼

無事同じ結果が出ました.
やはり,実数を何回も足していたのが原因でした.

私の些細なミスに対して,時間を割いてまで回答して頂きありがとうございました.
doradora55さんの欄にて回答して頂いた皆様にお礼を申し上げます.

投稿日時 - 2011-09-18 05:49:42

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

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

回答(5)

ANo.5

シミュレーションソフトを動かしていて計算式自体が同じソースコードなのに結果が微妙に違うことがあります。
今把握している(想像している?)原因としては
(1) 同じソースコードなのに、ループの中などに存在すると、コンパイラの最適化で式の順序が入れ替えられ、数学の式としては等価ですが、小数点誤差の蓄積され方が異なる。
(2) 割り算を高速化するために、逆数に変換してからかけ算をするように最適化されることもあります。直接割り算よりも速いですが、誤差が大きくなります。
(3) コンパイルするときにIEEE 754に完全には準拠していない演算になっていることが多いです。丸め誤差などが微妙に違うようです。

コンパイラの最適化なし(オプション-O0が多いです)でやってみたらどうですか?(1)と(2)はこれで避けられるはず。
(3)は別にオプションがあるかもしれませんし、-O0でIEEE754に準拠されるかは分かりません。私が使っているPGIコンパイラは別にあります。

普通の計算では目立たないのですが、このようなことがあると何万回も加算をすると差が出ます。

投稿日時 - 2011-09-17 22:54:39

ANo.4

0,01を25回足すのは、毎回、真の0.01との誤差が加わるので、誤差が蓄積されやすいです。
大使、25 * 0.01だと、真の0.01と0.01との誤差はこの時点では最小だし、かけ算は一時的により大きな桁で計算して結果をまるめる形になるので、誤差は小さくてすみます。

有限桁の2進浮動小数点を使った数値演算ではいろんなところで誤差が出るので、精度よく計算したいなら常に考えておく必要があります。

投稿日時 - 2011-09-17 21:47:26

ANo.3

最終的には同じ結果になるはずのものでも
浮動小数点演算があってその手順が異なるのであれば
演算誤差に差異があるのは当然かと思いますが。

そういう場合は許容誤差いくらかまでは同じとみなすとかするんじゃないかなぁ。

doubleやfloatが保持できるのは近似値というのは理解されていますよね?

投稿日時 - 2011-09-17 20:58:50

補足

近似値になると言うのはもちろん理解しています.
ただ,(1)は独立した関数Aをループさせているはずなので,
演算誤差も同じ値が出るのではないのですか?

ループ内の関数Aの演算が次のパラメータの際に影響するなら,
演算誤差は違う値になるのではないのかと思います.

違っていたら申し訳ございません.

投稿日時 - 2011-09-17 21:25:04

ANo.2

整数は2進数で正確に表せるが、小数部分は正確に表せないものがあるからです。
例えば、0.1は2進数でどう表すか調べてみてください。それを10倍してみてください。
浮動小数点をイコールで比較すると問題がでるのもそのためです。

投稿日時 - 2011-09-17 20:48:45

あなたにオススメの質問