首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >双精度除法不准确(Visual C++ 2008)

问双精度除法不准确(Visual C++ 2008)
EN

Stack Overflow用户
提问于 2009-05-23 19:48:57
回答 2查看 900关注 0票数 1

我有一些代码可以将从QueryPerformanceCounter返回的时间值转换为以毫秒为单位的双精度值,因为这样更便于计数。

该函数如下所示:

代码语言:javascript
复制
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++选项中的浮点模式设置为默认值( Precise (/fp:precise) )

代码语言:javascript
复制
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更高精度的类型?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2009-05-24 09:00:58

谢谢,使用decimal也可能是一种解决方案。现在,我采取了一种稍微不同的方法,这种方法也运行得很好,至少只要我的程序在不重启的情况下运行不超过一周左右。我只记得当我的程序启动时的性能计数器,并在转换为双精度并进行除法之前从当前计数器中减去它。

我不确定哪种解决方案是最快的,我想我必须首先对其进行基准测试。

代码语言:javascript
复制
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();
}
票数 0
EN

Stack Overflow用户

发布于 2009-05-23 20:59:14

阿迪恩

如果您不介意性能影响,请在执行除法之前将QuadPart数字转换为十进制而不是双精度。然后将得到的数字转换回双精度。

你对数字大小的估计是正确的。它抛弃了浮点计算的准确性。

有关这方面的更多信息,请参阅:

每个计算机科学家都应该知道的浮点算术http://docs.sun.com/source/806-3568/ncg_goldberg.html

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/902320

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档