首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Visual C++ math.h错误

Visual C++ math.h错误
EN

Stack Overflow用户
提问于 2009-09-01 17:29:21
回答 4查看 1.7K关注 0票数 4

我正在调试我的项目,但找不到bug。最后我找到了它。看看代码。你认为一切都很好,结果会是“好!”,不是吗?现在用VC编译(我已经尝试过vs2005和vs2008)。

代码语言:javascript
复制
#include <math.h>
#include <stdio.h>


int main () {
    for ( double x = 90100.0; x<90120.0; x+=1 )
    {
        if ( cos(x) == cos(x) )
            printf ("x==%f  OK!\n", x);
        else
            printf ("x==%f  FAIL!\n", x);
    }

    getchar();
    return 0; 
}

魔术双常数是90112.0。当x< 90112.0时,一切都可以,当x> 90112.0时--不行!您可以将cos更改为sin。

有什么想法吗?不要忘记,sin和cos是周期性的。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2009-09-01 17:36:05

可能是这样的:http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.18

我知道这很难接受,但是浮点运算并不像大多数人期望的那样工作。更糟糕的是,其中一些差异取决于特定计算机浮点硬件的细节和/或在特定编译器上使用的优化设置。你可能不喜欢这样,但事实就是这样。“得到它”的唯一方法是把你对事物应该如何表现的假设放在一边,接受事物实际表现的样子……

(重点是“经常”这个词;其行为取决于您的硬件、编译器等):浮点计算和比较通常由特殊硬件执行,这些硬件通常包含特殊寄存器,并且这些寄存器的位数通常比double多。这意味着中间浮点计算通常比sizeof(double)有更多的位数,当一个浮点值被写入内存时,它经常被截断,经常丢失一些位的精度...

只需记住这一点:浮点比较是棘手和微妙的,并且充满了危险。注意。浮点的实际工作方式与大多数程序员倾向于认为它应该工作的方式是不同的。如果你打算使用浮点,你需要了解它的实际工作原理...

票数 36
EN

Stack Overflow用户

发布于 2009-09-01 17:49:35

正如其他人所指出的,VS数学库在x87 FPU上进行计算,并生成80位的结果,即使类型是double。

因此:

调用

  1. cos( ),并在从x87堆栈中弹出80位浮点型
  2. cos(x)并将其作为双精度型存储到内存中时,返回位于x87堆栈顶部的cos(x);这会导致它四舍五入为64位浮点型,从而更改其值
  3. cos()被调用,并返回位于x87堆栈顶部的cos(x)作为80位浮点型
  4. 舍入值从内存加载到x87堆栈
  5. cos(X)的舍入和未舍入的值比较不相等。

许多数学库和编译器通过在SSE寄存器中执行64位浮点数(如果可用)进行计算,或者在比较之前强制存储和舍入值,或者通过在实际计算cos( )时存储并重新加载最终结果来保护您。你碰巧使用的编译器/库组合就不那么容易理解了。

票数 10
EN

Stack Overflow用户

发布于 2009-09-01 17:40:36

编译器可能生成了最终将64位双精度值与80位内部浮点寄存器进行比较的代码。测试浮点值的相等性很容易出现这样的错误--您几乎总是更好地进行“模糊”比较,比如(fabs(val1 - val2) < EPSILON)而不是(val1 == val2)。

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

https://stackoverflow.com/questions/1363665

复制
相关文章

相似问题

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