2009-05-23 8 views
1

QueryPerformanceCounterから返された時間値をミリ秒単位のdouble値に変換するコードがいくつかあります。double型の不正確な除算(Visual C++ 2008)

関数は次のようになります。

double timeGetExactTime() { 
    LARGE_INTEGER timerPerformanceCounter, timerPerformanceFrequency; 
    QueryPerformanceCounter(&timerPerformanceCounter); 
    if (QueryPerformanceFrequency(&timerPerformanceFrequency)) { 
     return (double)timerPerformanceCounter.QuadPart/(((double)timerPerformanceFrequency.QuadPart)/1000.0); 
    } 
    return 0.0; 
} 

私は(私は前にこの問題を抱えていたとは思わない、と何も変更がコードに行われていない)最近抱えている問題は、その結果でありますあまり正確ではありません。結果には小数点は含まれませんが、1ミリ秒よりも精度は低くなります。

デバッガで式を入力すると、予想通りの結果が得られます。

私は、64ビット整数の精度を保持することはできませんが、現時点でPerformanceCounterは46ビットしか必要としないことを理解しています(ダブルは52ビットを損失なしで格納できるはずです) さらに、デバッガが別の形式を使用して分割を実行することになります。

ここに私が得たいくつかの結果があります。プログラムはデバッグモードでコンパイルされた、C++オプションで浮動小数点モードがデフォルト(精密(/ FP:正確な))に設定した

timerPerformanceCounter.QuadPart: 30270310439445 
timerPerformanceFrequency.QuadPart: 14318180 
double perfCounter = (double)timerPerformanceCounter.QuadPart; 
30270310439445.000 

double perfFrequency = (((double)timerPerformanceFrequency.QuadPart)/1000.0); 
14318.179687500000 

double result = perfCounter/perfFrequency; 
2114117248.0000000 

return (double)timerPerformanceCounter.QuadPart/(((double)timerPerformanceFrequency.QuadPart)/1000.0); 
2114117248.0000000 

Result with same expression in debugger: 
2114117188.0396111 

Result of perfTimerCount/perfTimerFreq in debugger: 
2114117234.1810646 

Result of 30270310439445/14318180 in calculator: 
2114117188.0396111796331656677036 

精度がに比べデバッガのウォッチで異なる理由を誰もが知っています私のプログラムの結果は?

更新:変換と除算を実行する前に、timerPerformanceCounter.QuadPartから30270310439445を差し引いてみましたが、すべての場合に正確に表示されます。 私のコンピュータの稼働時間が今16日になっているので、私はこの動作を見ているだけなのかもしれません。 したがって、大きな数値では除算の精度の問題があるように見えますが、ウォッチウィンドウでディビジョンがまだ正しい理由はまだ説明されていません。 結果が倍精度よりも高い精度の型を使用していますか?

答えて

0

について知っておくべきことのおかげで、小数点を使用すると、おそらくあまりにも解決策になります。 今のところ私は若干異なるアプローチを取っていますが、少なくともプログラムが1週間程度以上は再起動せずに実行されない限り、うまくいきます。 プログラムの開始時のパフォーマンスカウンタを覚えておいて、現在のカウンタからこれを減算してからdoubleに変換し、除算を実行します。

どのソリューションが最速であるかわかりませんが、最初にベンチマークする必要があります。

bool perfTimerInitialized = false; 
double timerPerformanceFrequencyDbl; 
LARGE_INTEGER timerPerformanceFrequency; 
LARGE_INTEGER timerPerformanceCounterStart; 
double timeGetExactTime() 
{ 
    if (!perfTimerInitialized) { 
     QueryPerformanceFrequency(&timerPerformanceFrequency); 
     timerPerformanceFrequencyDbl = ((double)timerPerformanceFrequency.QuadPart)/1000.0; 
     QueryPerformanceCounter(&timerPerformanceCounterStart); 
     perfTimerInitialized = true; 
    } 

    LARGE_INTEGER timerPerformanceCounter; 
    if (QueryPerformanceCounter(&timerPerformanceCounter)) { 
     timerPerformanceCounter.QuadPart -= timerPerformanceCounterStart.QuadPart; 
     return ((double)timerPerformanceCounter.QuadPart)/timerPerformanceFrequencyDbl; 
    } 

    return (double)timeGetTime(); 
}
0

Adion、

あなたはパフォーマンスヒットを気にしない場合は、分割を行う前に、代わりに二重の小数ためにあなたのQuadPart番号をキャスト。その後、結果の数値を2倍にキャストします。

数字のサイズは正しいですか。浮動小数点計算の精度が低下します。あなたはおそらくこれまでに知りたいと思ったよりも、この詳細については

、以下を参照してください

すべてのコンピュータ科学者は、浮動小数点演算 http://docs.sun.com/source/806-3568/ncg_goldberg.html

関連する問題