1

QueryPerformanceCounter から返された時間値をミリ秒単位の double 値に変換するコードがいくつかあります。これは、カウントする方が便利だからです。

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

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

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

デバッガーに式を入力すると、期待どおりの正確な結果が得られます。

double は 64 ビット整数の精度を保持できないことは理解していますが、現時点では、PerformanceCounter は 46 ビットしか必要としませんでした (そして、double は損失なしで 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 日になり、値が以前よりも大きくなったためでしょうか? したがって、大きな数での除算の精度の問題であるように見えますが、ウォッチ ウィンドウで除算が依然として正しい理由はまだ説明されていません。結果に double よりも高精度の型を使用していますか?

4

2 に答える 2

0

アディオン、

パフォーマンスの低下を気にしない場合は、除算を実行する前に、QuadPart の数値を double ではなく 10 進数にキャストしてください。次に、結果の数値を double にキャストします。

あなたは数字の大きさについて正しいです。浮動小数点計算の精度が低下します。

おそらくこれまでに知りたかった以上の詳細については、次を参照してください。

すべてのコンピュータ科学者が浮動小数点演算について知っておくべきこと http://docs.sun.com/source/806-3568/ncg_goldberg.html

于 2009-05-23T20:59:13.640 に答える
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();
}
于 2009-05-24T09:00:57.953 に答える