[解決済み] 最適化を有効にすると浮動小数点演算の結果が異なる - コンパイラのバグ?
質問
以下のコードは、Visual Studio 2008で最適化ありでもなしでも動作します。しかし、それは唯一の最適化(O0)せずにg + +上で動作します。
#include <cstdlib>
#include <iostream>
#include <cmath>
double round(double v, double digit)
{
double pow = std::pow(10.0, digit);
double t = v * pow;
//std::cout << "t:" << t << std::endl;
double r = std::floor(t + 0.5);
//std::cout << "r:" << r << std::endl;
return r / pow;
}
int main(int argc, char *argv[])
{
std::cout << round(4.45, 1) << std::endl;
std::cout << round(4.55, 1) << std::endl;
}
と出力されるはずです。
4.5
4.6
しかし、最適化されたg++ (
O1
-
O3
) が出力されます。
4.5
4.5
を追加すると
volatile
をつけるとうまくいくので、何か最適化のバグがあるのでしょうか?
g++ 4.1.2、4.4.4でテストしています。
以下はideoneでの結果です。 http://ideone.com/Rz937
そして、g++でテストするオプションはシンプルです。
g++ -O2 round.cpp
もっと面白いのは
/fp:fast
をオンにした場合でも、結果は正しく表示されます。
さらなる質問です。
私は疑問に思ったのですが、常に
-ffloat-store
をオンにする必要があるのでしょうか?
なぜなら、私がテストした g++ のバージョンは で出荷されています。 CentOS / レッドハットリナックス 5 および CentOS/Redhat 6 .
これらのプラットフォームで多くのプログラムをコンパイルしましたが、プログラム内に予期せぬバグが発生しないか心配です。私の C++ コードと使用したライブラリのすべてにそのような問題があるかどうかを調査するのは少し難しいようです。何か提案はありますか?
であっても、なぜ
/fp:fast
をオンにしても、Visual Studio 2008 が動作するのはなぜか?この問題では、Visual Studio 2008 の方が g++ よりも信頼性が高いような気がしますが?
どのように解決するのですか?
Intel x86 プロセッサは、内部で 80 ビット拡張精度を使用するのに対し
double
は通常 64 ビット幅です。異なる最適化レベルは、CPU からの浮動小数点値がメモリに保存され、その結果 80 ビット精度から 64 ビット精度に丸められる頻度に影響を及ぼします。
を使用します。
-ffloat-store
gccオプションを使用すると、異なる最適化レベルで同じ浮動小数点結果を得ることができます。
別の方法として
long double
型は、80ビットから64ビット精度への丸めを避けるために、gccでは通常80ビット幅です。
man gcc
がすべてを語っています。
-ffloat-store
Do not store floating point variables in registers, and inhibit
other options that might change whether a floating point value is
taken from a register or memory.
This option prevents undesirable excess precision on machines such
as the 68000 where the floating registers (of the 68881) keep more
precision than a "double" is supposed to have. Similarly for the
x86 architecture. For most programs, the excess precision does
only good, but a few programs rely on the precise definition of
IEEE floating point. Use -ffloat-store for such programs, after
modifying them to store all pertinent intermediate computations
into variables.
x86_64 ビルドでは、コンパイラは SSE レジスタを次のように使用します。
float
と
double
をデフォルトで使用することで、拡張精度が使用されず、この問題が発生しないようにしました。
gcc
コンパイラオプション
-mfpmath
はそれを制御します。
関連
-
[解決済み】非静的メンバ関数への参照を呼び出す必要がある
-
[解決済み】変数 '' を抽象型 '' と宣言できない。
-
[解決済み】テンプレートの引数1が無効です(Code::Blocks Win Vista) - テンプレートは使いません。
-
[解決済み】C++エラー:の初期化に一致するコンストラクタがありません。
-
[解決済み] 非常に基本的なC++プログラムの問題 - バイナリ式への無効なオペランド
-
[解決済み】c++でstd::vectorを返すための効率的な方法
-
[解決済み】エラー。switchステートメントでcaseラベルにジャンプする
-
[解決済み】Visual Studio 2013および2015でC++コンパイラーエラーC2280「削除された関数を参照しようとした」が発生する
-
[解決済み】標準ライブラリにstd::endlに相当するタブはあるか?
-
[解決済み】VC++の致命的なエラーLNK1168:書き込みのためにfilename.exeを開くことができません。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】 unsigned int vs. size_t
-
[解決済み】C++でランダムな2倍数を生成する
-
[解決済み] error: 'if' の前に unqualified-id を期待した。
-
[解決済み】'cout'は型名ではない
-
[解決済み】クラステンプレートの使用にはテンプレート引数リストが必要です
-
[解決済み] [Solved] インクルードファイルが開けません。'stdio.h' - Visual Studio Community 2017 - C++ Error
-
[解決済み】なぜ、サイズ8の初期化されていない値を使用するのでしょうか?
-
[解決済み] to_string は std のメンバーではない、と g++ が言っている (mingw)
-
[解決済み】Visual Studioのデバッガーエラー。プログラムを開始できません 指定されたファイルが見つかりません
-
[解決済み] int型へのキャスト vs フロア