Domanda

Ho qualche codice per convertire un valore di tempo tornato da QueryPerformanceCounter per un valore doppio in millisecondi, in quanto questo è più conveniente a contare con.

La funzione è simile al seguente:

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

Il problema che sto avendo di recente (non credo che ho avuto questo problema prima, e non sono state apportate modifiche al codice) è che il risultato non è molto preciso. Il risultato non contiene decimali, ma è anche meno preciso di 1 millisecondo.

Quando entro l'espressione nel debugger, il risultato è preciso come mi sarei aspettato.

Ho capito che una doppia non può tenere la precisione di un intero a 64 bit, ma in questo momento, l'PerformanceCounter richiesto solo 46 bit (e un letto dovrebbe essere in grado di memorizzare 52 bit senza perdita) Inoltre sembra strano che il debugger potrebbe utilizzare un formato diverso per fare la divisione.

Qui ci sono alcuni risultati che ho ottenuto. Il programma è stato compilato in modalità debug, Modalità a virgola mobile in C ++ opzioni è stato fissato al valore predefinito (Precise (/ fp: precise))

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

Qualcuno sa il motivo per cui la precisione è diversa a Watch del debugger rispetto al risultato nel mio programma?

Aggiornamento: Ho provato detraendo 30.270.310,439445 millions da timerPerformanceCounter.QuadPart prima di fare la conversione e la divisione, e in quanto sembra di essere precisi in tutti i casi ora. Forse il motivo per cui sto solo vedendo questo comportamento ora potrebbe essere perché i tempi di attività del mio computer è ora 16 giorni, in modo che il valore è maggiore di quanto mi sono abituato? In modo che non sembra essere un problema di precisione di divisione con i grandi numeri, ma che ancora non spiega perché la divisione è stata ancora corretta nella finestra di controllo. La usa un tipo più elevata precisione del doppio per i suoi risultati?

È stato utile?

Soluzione 2

Grazie, utilizzando decimale probabilmente sarebbe una soluzione troppo. Per ora mi sono preso un approccio leggermente diverso, che funziona anche bene, almeno finché il mio programma non viene eseguito più di una settimana o giù di lì senza riavviare. Ricordo solo il contatore delle prestazioni di quando il mio programma è iniziato, e sottrarre questo dal banco corrente prima della conversione per raddoppiare e fare la divisione.

Non sono sicuro di quale soluzione sarebbe più veloce, credo che avrei dovuto benchmark che prima.

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

Altri suggerimenti

Adion,

Se non ti dispiace il calo di prestazioni, lanciare i numeri QuadPart a decimale al posto del doppio prima di eseguire la divisione. Poi gettato il numero risultante di nuovo al doppio.

Siete corretto circa la dimensione dei numeri. Si getta via l'accuratezza dei calcoli in virgola mobile.

Per ulteriori informazioni su questo che probabilmente mai voluto sapere, vedere:

Ciò che ogni Computer Scientist dovrebbe sapere aritmetica alla virgola mobile http://docs.sun.com/source/806-3568/ncg_goldberg. html

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top