17

問題。

Microsoft Visual C ++ 2005コンパイラ、32ビットWindows XP SP3、AMD 64 X2 CPU

コード:

double a = 3015.0; 
double b = 0.00025298219406977296;
//*((unsigned __int64*)(&a)) == 0x40a78e0000000000  
//*((unsigned __int64*)(&b)) == 0x3f30945640000000  
double f = a/b;//3015/0.00025298219406977296;

計算結果(つまり「f」)は11917835.000000000(((unsigned __int64)(&f))== 0x4166bb4160000000)ですが、11917834.814763514(つまり((unsigned __int64)(&f))== 0x4166bb415a128aef)である必要があります。
つまり、小数部分が失われます。
残念ながら、正確にするために小数部分が必要です。

質問:
1)なぜこれが起こるのですか?
2)どうすれば問題を解決できますか?

追加情報:
0)結果は「ウォッチ」ウィンドウから直接取得されます(印刷されなかったため、印刷精度を設定することを忘れませんでした)。浮動小数点変数の16進ダンプも提供したので、計算結果は間違いありません。
1)f = a/bの分解は次のとおりです。

fld         qword ptr [a]  
fdiv        qword ptr [b]  
fstp        qword ptr [f]  

2)f = 3015 / 0.00025298219406977296; 正しい結果が得られます(f == 11917834.814763514、((unsigned __int64)(&f))== 0x4166bb415a128aef)が、この場合、結果はコンパイル時に単純に計算されるように見えます。

fld         qword ptr [__real@4166bb415a128aef (828EA0h)]  
fstp        qword ptr [f]  

では、どうすればこの問題を解決できますか?

PS一時的な回避策を見つけました(除算の小数部分のみが必要なので、現時点ではf = fmod(a / b)/ bを使用しています)が、この問題を適切に修正する方法を知りたいです-倍精度は小数点以下16桁であると想定されているため、このような計算で問題が発生することはありません。

4

5 に答える 5

15

プログラムでdirectxを使用している場合、デバイスを作成するときに特に指示しない限り、浮動小数点ユニットが単精度モードに切り替えられ、これが正確に発生します。

于 2010-03-28T18:16:55.020 に答える
4

興味深いことに、aとbの両方をfloatとして宣言すると、正確に11917835.000000000になります。したがって、定数の解釈方法または後で計算のいずれかで、単精度への変換がどこかで発生していると思います。

ただし、コードがいかに単純であるかを考えると、どちらの場合も少し驚くべきことです。エキゾチックなコンパイラ指令を使用しておらず、すべての浮動小数点数に単精度を強制していますか?

編集:コンパイルされたプログラムが誤った結果を生成することを実際に確認しましたか?それ以外の場合、(誤った)単精度変換の最も可能性の高い候補はデバッガーです。

于 2010-03-28T17:47:04.390 に答える
2

正確な計算が必要な場合は、浮動小数点を使用しないでください。

自分に有利に働き、有理数をサポートするBigNumライブラリを入手してください。

于 2010-03-28T17:47:33.500 に答える
1

精度を指定せずに数値を印刷していると思います。これを試して:

#include <iostream>
#include <iomanip>

int main() { 
    double a = 3015.0; 
    double b = 0.00025298219406977296;
    double f = a/b;

    std::cout << std::fixed << std::setprecision(15) << f << std::endl;
    return 0;
}

これにより、次のものが生成されます。

11917834.814763514000000

これは私には正しいように見えます。2005ではなくVC++2008を使用していますが、違いはコンパイラではなくコードにあると思います。

于 2010-03-28T17:13:05.420 に答える
0

fstp命令の直後にfの値を調べていますか?最適化をオンにしている場合は、ウォッチウィンドウに後で取得した値が表示されている可能性があります(後でfの小数部分を見ていると言うと、これは少し妥当なようです-いくつかの命令がそれをマスクしてしまいますか?どういうわけか?)

于 2010-03-28T17:58:24.783 に答える