双打的不准确的除法(视觉C ++ 2008)
题
我有一些代码转换从QueryPerformanceCounter的返回以毫秒为单位的双精度值的时间值,因为这是更方便的与计数。
该函数如下所示:
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天,所以价值比我已经习惯了更大? 因此,它似乎是一个分割精度问题有大量,但仍然无法解释为什么分工仍然在监视窗口中正确。 是否使用更高精度的类型比双为它的结果吗?
解决方案 2
谢谢,使用小数可能会是一个溶液太。 现在,我已经采取了稍微不同的方法,这也是行之有效的,至少只要我的程序不,无需重新启动运行超过一个星期左右的时间。 我只记得我的程序启动时的性能计数器,以及将翻番,做除法之前从当前计数器减去这一点。
我不知道该解决方案将是最快的,我想我不得不基准,第一。
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,
如果你不介意的性能损失,投你QuadPart号为十进制而不是双执行除法之前。然后将所得的数转换回双
您是对数字的大小是正确的。它抛出了浮点计算的准确性。
有关更多关于这可能比你想知道的,请参阅:
什么每台计算机科学家应该知道关于浮点运算 http://docs.sun.com/source/806-3568/ncg_goldberg。 HTML