Pergunta

Eu tenho algum código para converter um valor de tempo voltou de QueryPerformanceCounter para um valor double em milissegundos, como este é mais conveniente para contar com.

A função esta aparência:

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

O problema que estou tendo recentemente (eu não acho que eu tive esse problema antes, e não foram feitas alterações ao código) é que o resultado não é muito preciso. O resultado não contém casas decimais, mas é ainda menos preciso do que 1 milissegundo.

Quando eu digitar a expressão no depurador, o resultado é tão preciso quanto eu esperaria.

Eu entendo que a dupla pode não manter a precisão de um inteiro de 64 bits, mas, neste momento, o PerformanceCounter necessária apenas 46 bits (e um duplo deve ser capaz de armazenar 52 bits sem perda) Além disso, parece estranho que o depurador iria usar um formato diferente para fazer a divisão.

Aqui estão alguns resultados que obtive. O programa foi compilado no modo de depuração, Flutuar modo Point em C ++ opções foi definido como o padrão (Precise (/ fp: precisa))

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

Alguém sabe por que a precisão é diferente em Watch do depurador em comparação com o resultado em meu programa?

Update: Eu tentei dedução 30270310439445 de timerPerformanceCounter.QuadPart antes de fazer a conversão e divisão, e que parece ser precisas em todos os casos agora. Talvez a razão pela qual eu só estou vendo esse comportamento agora pode ser porque o tempo de funcionamento do meu computador tem agora 16 dias, então o valor é maior do que eu estou acostumado a? Por isso, parece ser uma questão de precisão divisão com números grandes, mas que ainda não explica por que a divisão ainda estava correta na janela Watch. Ele usa um tipo de maior precisão do que o dobro para os seus resultados?

Foi útil?

Solução 2

Obrigado, usando decimal seria provavelmente uma solução também. Por agora eu tenho tido uma abordagem ligeiramente diferente, que também funciona bem, pelo menos tão longo como o meu programa não executar mais de uma semana ou assim sem reiniciar. Eu só me lembro o contador de quando o meu programa começou performance, e subtrair isso a partir do contra-corrente antes de converter para dobrar e fazer a divisão.

Eu não tenho certeza qual solução seria mais rápido, acho que eu teria que benchmark que em primeiro lugar.

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();
}

Outras dicas

Adion,

Se você não se importa o impacto no desempenho, lança seus números QuadPart para decimal em vez de duas vezes antes de executar a divisão. Em seguida, emitir o número de volta, resultando para o dobro.

Você está correto sobre o tamanho dos números. Ele joga fora a precisão dos cálculos de ponto flutuante.

Para saber mais sobre isso do que você provavelmente sempre quis saber, ver:

O que cada cientista computador deve saber sobre Floating-Point Arithmetic http://docs.sun.com/source/806-3568/ncg_goldberg. html

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top