ouble の計算結果が状況によっておかしくなる場合があるのですが、
理由がなかなか分からないので心当たりがあれば教えてもらえませんか。
問題のコードを簡略化したのが以下です。
------------------------------------
void calc(double *result) {
const double mPI2 = 1.5707963267948966;
double b_arc;
b_arc の計算 … (1)
// printf("test"); … (2)
*result = mPI2 - b_arc; … (3)
}
------------------------------------
おかしくなるのは(3)の *result の値です。
(3)での b_arc、mPI2 の値を出力してみると
b_arc: [1.57079632679489660000000000000000000000]
mPI2: [1.57079632679489660000000000000000000000]
となり、mPI2 == b_arc の結果も true になります。
さらに、バイナリで見ても二つは全く同じ値でした。
なので *result は 0 になるはずなのですが、これが 0 にならない場合があります。
色々な状態で試したところ結果は以下のようになりました。
1. Windows7 : 0
2. WindowsXP : -0.000000000000000001951563910473908
3. WindowsXPのデバッグビルド : 0
4. WindowsXPで(2)(2)のコメントアウトを外し printf をいれる : 0
WindowsXPのリリースビルドだけ 0 にならず、 -0.000000000000000001951563910473908 になります。
4は理由が分からないのですが、(2)の位置になんらかの処理をいれると結果が 0 になります。
ちなみにVC++ではなくQTというFrameworkを使って作っています。
よろしくお願いします。
No.3ベストアンサー
- 回答日時:
おそらく、下記リンクにあるような浮動小数用レジスタの扱いが原因だと思います。
http://0xcc.net/blog/archives/000164.html
doubleはメモリ上では64bitですが、実際にプロセッサ内で計算する場合には、モードや動作環境にもよりますが64bit以上のサイズのレジスタ(80bit)が使われることが多いようです。
したがって、レジスタにはいっている値をメモリに戻す時に精度の低下が発生します。
b_arc: [1.57079632679489660000000000000000000000]
とありますが、プロセッサ内で浮動小数演算を連続して実行し続けている場合、レジスタ内ではもう少し値が入っており、
b_arc: [1.5707963267948966********]
という感じになっているはずです。そこから
mPI2: [1.57079632679489660000000000000000000000]
を引くため、正しい計算結果としては 0.0000000000000000******** となり、この差分が
> 2. WindowsXP : -0.000000000000000001951563910473908
では無いかと思います。
> 4は理由が分からないのですが、(2)の位置になんらかの処理をいれると結果が 0 になります。
というのは、途中で別の命令が入ってくるため浮動小数演算がいったん中断され、80bitレジスタの値を64bitのメモリにダウンコンバートしながら移動する、すなわちb_arcの値を
[1.5707963267948966*****] → [1.57079632679489660000000000000000000000]
と変換する処理が途中に入ってしまい、結果としてmPi2==b_arcとなっている、というのが理由だと思います。
どうもありがとうございます。
リンクも参考になりました。
No1の方も同じことをおっしゃっていますし、
その可能性が高いということで対応していこうと思います。
No.2
- 回答日時:
余談ですが「VC++ではなくQTというFrameworkを使って作っています」といわれてもねぇ.
コンパイラを確定させてほしい....
No.1
- 回答日時:
憶測ですが……。
b_arc の計算で、三角関数の計算があるとして、
b_arc に結果が代入される直前の、拡張精度(double より、さらに桁数の多い計算、計算の中間で使われることはある)の変数を、最適化の結果として、*result への代入に使っているのではないかなという気はします。
だから、result への代入の前に別の処理が入ると、この最適化ができずに、b_arc の値をまじめに使って計算しているとか。
アセンブラに落ちた結果を確認すると良いですが。
もしくは、リリースビルドの最適化をOFFにして結果がどう変わるか確認してみるとか。
回答ありがとうございます。
確かにそれだと何か処理をいれると値が変わることに説明がつきますね。
ネットで調べてみたのですが、アセンブラは値が見れませんでした。
全然アセンブラの知識がないので調べるのはちょっと時間がかかりそうです。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# (C言語)めちゃくちゃな値になってしまいます。 5 2022/08/13 11:55
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# c言語について 下記の計算結果を出力するコードを記述する問題で 0-4 3.14×2 5÷3 30÷ 5 2022/05/17 22:41
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- その他(プログラミング・Web制作) python OpenPyXLを使って出力結果をエクセルに書き込み 2 2022/06/04 19:46
- C言語・C++・C# C++のcinの動作 5 2023/02/26 00:13
- C言語・C++・C# このプログラミングの問題を教えてほしいです。 キーボードからデータ数nとn個のデータを入力し、平均値 3 2022/12/19 22:51
- C言語・C++・C# C++で割り算の結果を昇順に出力するプログラムを作りたいのですが、例えば(double)100000 3 2022/07/15 17:46
- C言語・C++・C# c言語でユーザ関数を利用して複素数のべき乗と絶対値の数列を計算するプログラムが作りたいです。 3 2023/01/29 22:13
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
O(n log n)について2
-
16進数 加算 減算 C言語
-
三菱シーケンサ(Aシリーズ)で...
-
ExcelでPC(パソコン)によって...
-
c languageで 簡単な質問があ...
-
VB.net Double と...
-
C言語でセルオートマトンを作成...
-
Log関数に関する質問
-
VBAでミリ秒まで出力する方法
-
距離から緯度経度を求める方法
-
乱数 なぜ剰余を使うのか
-
大きすぎる数値になるとE+にな...
-
色の判定
-
【C言語】RGBと輝度の計算に関して
-
100桁の計算ができなくて困って...
-
16進数とかわからないです
-
”/”を使わずに割り算したいんで...
-
データ型 double の桁数について
-
計算に誤差が出る?
-
【VBA、VBS】何故False・・・?
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
O(n log n)について2
-
16進数 加算 減算 C言語
-
c languageで 簡単な質問があ...
-
VB.net Double と...
-
”/”を使わずに割り算したいんで...
-
三菱シーケンサ(Aシリーズ)で...
-
ExcelのINT関数の計算結果がお...
-
有効数字について 以前質問をし...
-
ExcelでPC(パソコン)によって...
-
除算を使わずに10で割りたい。
-
EXCELの関数"STDEV(標準偏差)"...
-
floatの有効桁数
-
VBAでミリ秒まで出力する方法
-
100桁の計算ができなくて困って...
-
2進数の足し算(C言語)
-
VB6.0での小数点の扱いについて
-
VBAでの割り算の余りの求め方
-
コンピューターは指数関数をど...
-
距離から緯度経度を求める方法
-
BCD・HEX・BINについて
おすすめ情報