首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >无限循环heisenbug:如果我添加打印输出,它就会退出。

无限循环heisenbug:如果我添加打印输出,它就会退出。
EN

Stack Overflow用户
提问于 2015-02-25 15:17:29
回答 2查看 1.7K关注 0票数 12

这是我的源代码:

代码语言:javascript
复制
#include <iostream>
#include <cmath>

using namespace std;

double up = 19.0 + (61.0/125.0);
double down = -32.0 - (2.0/3.0);
double rectangle = (up - down) * 8.0;

double f(double x) {
    return (pow(x, 4.0)/500.0) - (pow(x, 2.0)/200.0) - 0.012;
}

double g(double x) {
    return -(pow(x, 3.0)/30.0) + (x/20.0) + (1.0/6.0);
}

double area_upper(double x, double step) {
    return (((up - f(x)) + (up - f(x + step))) * step) / 2.0;
}

double area_lower(double x, double step) {
    return (((g(x) - down) + (g(x + step) - down)) * step) / 2.0;
}

double area(double x, double step) {
    return area_upper(x, step) + area_lower(x, step);
}

int main() {
    double current = 0, last = 0, step = 1.0;
    
    do {
        last = current;
        step /= 10.0;
        current = 0;
        
        for(double x = 2.0; x < 10.0; x += step) current += area(x, step);
        
        current = rectangle - current;
        current = round(current * 1000.0) / 1000.0;
        //cout << current << endl;
    } while(current != last);
    
    cout << current << endl;
    return 0;
}

它所做的是计算曲线之间的面积。main()中有一个循环-它的目的是在小数点3位内尽可能精确地计算值。

它没有起作用。为了调试起见,我添加了一行,这是唯一的注释行。我想知道循环里发生了什么。

代码语言:javascript
复制
//cout << current << endl;

当行在那里时--当我取消评论时--一切正常。当它不是-循环似乎是无限的。

天哪,怎么了?

我知道,这不是浮点数字不精确的问题。当我在循环中输出当前值时,所有内容都在循环内容的4次重复中完成。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-02-25 15:30:39

@Skizz的评论给出了可能的问题,但要详细说明:

浮点数学是很棘手的,尤其是舍入错误经常会出现。像1/1000.0这样的数字( round调用的结果)不能精确地用浮点表示。

一个更复杂的问题是,一方面是速度,另一方面是一致、直观的结果。例如,英特尔处理器的FPU以80位扩展精度格式存储值,而C/C++ double通常为64位。为了提高性能,编译器可能会将值保留在FPU中,作为80位临时代码,尽管这可能会产生与将它们截断为64位时不同的结果。

启用调试语句后,可能会将current存储到内存中,将其截断为64位,从而允许与last进行直接比较。

如果禁用了调试语句,current很可能是存储在FPU寄存器中的80位值,因此它永远不能等于last,只要last是64位值,并且它们都试图存储x/1000.0的不精确浮点表示。

解决方案是使用floating point comparison with some allowed error (因为直接检查浮点是否相等是一个好主意)。

进一步的注意:我还没有查看程序集输出来验证是否是这样的;如果需要,您可以自己完成。只有当我启用优化时,我才能重现这个问题。您可以通过调整编译器标志来“修复”错误,以选择一致性而不是速度,但正确的解决方案是使用不精确的比较,而不是直接检查是否相等。

票数 25
EN

Stack Overflow用户

发布于 2015-02-25 15:36:57

而不是

代码语言:javascript
复制
while(current != last);

使用这样的方法:

代码语言:javascript
复制
while(fabs(current - last) > tolerence);

其中tolerance可能是一个很小的数字,比如1.0e-6

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

https://stackoverflow.com/questions/28722647

复制
相关文章

相似问题

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