복식 부정확 한 부서 (Visual C ++ 2008)
문제
QueryPerformanCecocounter에서 리턴 된 시간 값을 밀리 초의 이중 값으로 변환하는 코드가 있습니다.
함수는 다음과 같습니다.
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 비트 정수의 정확도를 유지할 수 없다는 것을 이해하지만, 현재로서는 성능이 46 비트 만 필요하다 (그리고 더블은 손실없이 52 비트를 저장할 수 있어야한다) 더 나아가서 디버거가 사용하는 것은 이상하게 보인다. 부서를 수행 할 다른 형식.
다음은 내가 얻은 몇 가지 결과입니다. 이 프로그램은 디버그 모드로 컴파일되었으며 C ++ 옵션의 부동 소수점 모드는 기본값으로 설정되었습니다 (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
내 프로그램의 결과와 비교하여 디버거 시계에서 정확도가 왜 다른지 아는 사람이 있습니까?
업데이트 : TimerperFormanCecounter.quadPart에서 변환 및 부서를 수행하기 전에 30270310439445를 공제하려고 시도했지만 현재 모든 경우에 정확한 것으로 보입니다. 어쩌면 내가이 행동 만보고있는 이유는 컴퓨터의 가동 시간이 이제 16 일이기 때문에 값이 내가 익숙한 것보다 더 크기 때문일 수 있습니까? 따라서 많은 수의 부서 정확도 문제 인 것처럼 보이지만 여전히 시계 창에서 디비전이 여전히 올바른 이유를 설명하지 않습니다. 결과에 대해 더블보다 높은 정밀 유형을 사용합니까?
해결책 2
고마워요, 10 진수를 사용하는 것도 해결책이 될 것입니다. 지금은 약간 다른 접근 방식을 취했는데,이 방법은 적어도 내 프로그램이 다시 시작하지 않고 일주일 이상 실행되지 않는 한 잘 작동합니다. 프로그램이 시작된 시점의 성능 카운터를 기억하고,이를 현재 카운터에서 빼기 전에 두 배로 변환하고 부서를 수행합니다.
어떤 솔루션이 가장 빠른지 잘 모르겠습니다. 먼저 벤치마킹해야한다고 생각합니다.
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();
}
다른 팁
adion,
성능이 히트를 신경 쓰지 않으면 디비전을 수행하기 전에 쿼드 파트 번호를 더블 대신 10 진수로 시전하십시오. 그런 다음 결과 숫자를 다시 두 배로 돌리십시오.
당신은 숫자의 크기에 대해 맞습니다. 부동 소수점 계산의 정확도를 벗어납니다.
아마 알고 싶었던 것보다 이것에 대한 자세한 내용은 다음을 참조하십시오.
모든 컴퓨터 과학자가 부동 소수점 산술에 대해 알아야 할 것http://docs.sun.com/source/806-3568/ncg_goldberg.html