
C++でプログラミングの勉強をしています.
以下の現象で悩んでいます.
ある実数演算(double)をする関数A(実数パラメータxを用いた積算)を
以下の2種類の方法で用いると,結果が微妙に変わってしまいます.
(1)パラメータxを微小に変化させながら,関数Aをfor文でループさせ,最後の結果を入手する.
(xを変化させても,Aの結果が変わらないようにその他の変数を初期化しているのですが・・・)
(2) (1)の最終条件(パラメータxの大きさ)を同じにして,関数Aを1回のみ用いて,結果を入手する.
条件は同じはずなので,同じ結果が出て欲しいのですが,
結果が変わってしまい困っています.
この場合考えられる原因としては何があるでしょうか?
・前のパラメータの時の実数演算の誤差が積み重なっている可能性はありますか?
(でも,ループ中に共有している変数は必ず初期化しているのですが・・・)
ソースコードは複雑なため,載せることはできません.
大変申し訳ございません.
原因としてどんなことが考えられるのかを教えて頂けると助かります.
宜しくお願い致します.
No.1ベストアンサー
- 回答日時:
パラメータをたとえば0→1の間で10000分割した場合、
forループで1万回0.0001を加算して最後に1になった場合
の結果を出していれば、誤差で一致しない可能性があると思います。
0.0001×10000でも誤差が出るでしょう。
今思いついたのはその位です。
この回答への補足
回答の通りかもしれません.
(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
無事同じ結果が出ました.
やはり,実数を何回も足していたのが原因でした.
私の些細なミスに対して,時間を割いてまで回答して頂きありがとうございました.
doradora55さんの欄にて回答して頂いた皆様にお礼を申し上げます.
No.5
- 回答日時:
シミュレーションソフトを動かしていて計算式自体が同じソースコードなのに結果が微妙に違うことがあります。
今把握している(想像している?)原因としては
(1) 同じソースコードなのに、ループの中などに存在すると、コンパイラの最適化で式の順序が入れ替えられ、数学の式としては等価ですが、小数点誤差の蓄積され方が異なる。
(2) 割り算を高速化するために、逆数に変換してからかけ算をするように最適化されることもあります。直接割り算よりも速いですが、誤差が大きくなります。
(3) コンパイルするときにIEEE 754に完全には準拠していない演算になっていることが多いです。丸め誤差などが微妙に違うようです。
コンパイラの最適化なし(オプション-O0が多いです)でやってみたらどうですか?(1)と(2)はこれで避けられるはず。
(3)は別にオプションがあるかもしれませんし、-O0でIEEE754に準拠されるかは分かりません。私が使っているPGIコンパイラは別にあります。
普通の計算では目立たないのですが、このようなことがあると何万回も加算をすると差が出ます。
No.4
- 回答日時:
0,01を25回足すのは、毎回、真の0.01との誤差が加わるので、誤差が蓄積されやすいです。
大使、25 * 0.01だと、真の0.01と0.01との誤差はこの時点では最小だし、かけ算は一時的により大きな桁で計算して結果をまるめる形になるので、誤差は小さくてすみます。
有限桁の2進浮動小数点を使った数値演算ではいろんなところで誤差が出るので、精度よく計算したいなら常に考えておく必要があります。
No.3
- 回答日時:
最終的には同じ結果になるはずのものでも
浮動小数点演算があってその手順が異なるのであれば
演算誤差に差異があるのは当然かと思いますが。
そういう場合は許容誤差いくらかまでは同じとみなすとかするんじゃないかなぁ。
doubleやfloatが保持できるのは近似値というのは理解されていますよね?
この回答への補足
近似値になると言うのはもちろん理解しています.
ただ,(1)は独立した関数Aをループさせているはずなので,
演算誤差も同じ値が出るのではないのですか?
ループ内の関数Aの演算が次のパラメータの際に影響するなら,
演算誤差は違う値になるのではないのかと思います.
違っていたら申し訳ございません.
No.2
- 回答日時:
整数は2進数で正確に表せるが、小数部分は正確に表せないものがあるからです。
例えば、0.1は2進数でどう表すか調べてみてください。それを10倍してみてください。
浮動小数点をイコールで比較すると問題がでるのもそのためです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
有効数字について 以前質問をし...
-
c languageで 簡単な質問があ...
-
VB.net Double と...
-
浮動小数点演算を固定小数点演...
-
VB6.0での小数点の扱いについて
-
UTF8からUnicode(コードポイン...
-
データ型 double の桁数について
-
VBAのINT関数について
-
ExcelのINT関数の計算結果がお...
-
計算の丸め誤差の解消について
-
ExcelでPC(パソコン)によって...
-
大きすぎる数値になるとE+にな...
-
VBAでミリ秒まで出力する方法
-
O(n log n)について2
-
応用数学
-
Enterキーを押されたら次の処理...
-
Aの値からBの値を除するとは??
-
「Aに対するBの割合」と「Aに対...
-
C言語での引数の省略方法
-
ある商品のロス率を5%見込み、...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
有効数字について 以前質問をし...
-
c languageで 簡単な質問があ...
-
ExcelでPC(パソコン)によって...
-
O(n log n)について2
-
2進数の足し算(C言語)
-
16進数 加算 減算 C言語
-
EXCELの関数"STDEV(標準偏差)"...
-
三菱シーケンサ(Aシリーズ)で...
-
VB.net Double と...
-
MATLABでの行列の全要素の和
-
除算を使わずに10で割りたい。
-
floatの有効桁数
-
”/”を使わずに割り算したいんで...
-
ExcelのINT関数の計算結果がお...
-
VBAでミリ秒まで出力する方法
-
VB6.0での小数点の扱いについて
-
Fortran において変数の定義
-
計算の丸め誤差の解消について
-
C言語について質問です。
-
CRCの計算方法について
おすすめ情報