【问题标题】:Recursion on Integration Approximation Function积分逼近函数的递归
【发布时间】:2011-10-09 16:57:10
【问题描述】:

我正在尝试使用自适应梯形规则来近似积分。

我有一个粗略的积分近似:

//Approximates the integral of f across the interval [a,b]
double coarse_app(double(*f)(double x), double a, double b) {
    return (b - a) * (f(a) + f(b)) / 2.0;
}

我有一个很好的积分近似:

//Approximates the integral of f across the interval [a,b]
double fine_app(double(*f)(double x), double a, double b) {
    double m = (a + b) / 2.0;
    return (b - a) / 4.0 * (f(a) + 2.0 * f(m) + f(b));
}

这是通过对给定间隔的递减部分的近似求和来实现自适应的,直到递归级别太高或粗略和精细近似彼此非常接近:

//Adaptively approximates the integral of f across the interval [a,b] with
//    tolerance tol.
double trap(double(*f)(double x), double a, double b, double tol) {
    double q = fine_app(f, a, b);
    double r = coarse_app(f, a, b);
    if ((currentLevel >= minLevel) && (abs(q - r) <= 3.0 * tol)) {
        return q;
    } else if (currentLevel >= maxLevel) {
        return q;
    } else {
        ++currentLevel;
        return (trap(f, a, b / 2.0, tol / 2.0) + trap(f, a + (b / 2.0), b, tol / 2.0));
    }
}

如果我通过将积分分解为多个部分并在其上使用fine_app 来手动计算积分,我会得到一个非常好的近似值。但是,当我使用应该为我执行此操作的陷阱功能时,我的所有结果都太小了。

例如,trap(square, 0, 2.0, 1.0e-2) 给出输出 0.0424107,其中 square 函数定义为 x^2。但是,输出应该在 2.667 左右。这比在整个时间间隔上执行一次fine_app 差得多,它的值是 3。

从概念上讲,我相信我已经正确实现了它,但是关于 C++ 递归的某些东西并没有达到我的预期。

第一次使用 C++ 编程,因此欢迎所有改进。

【问题讨论】:

  • currentLevel 在哪里定义?我在您的代码中看不到它。如果它是一个全局变量,那么你做错了什么。
  • 是的,我将 currentLevel 定义为全局变量。谢谢你的回答,在下面。我会更彻底地看一遍。

标签: c++ math


【解决方案1】:

我假设您在其他地方定义了 currentLevel。你不想那样做。您还错误地计算了中点。

取 a = 3,b = 5:

[a, b / 2.0] = [3, 2.5]
[a + b / 2.0, b] = 2.5, 3]

正确的点应该是[3, 4]和[4, 5]

代码应如下所示:

double trap(double(*f)(double x), double a, double b, double tol, int currentLevel) {
    double q = fine_app(f, a, b);
    double r = coarse_app(f, a, b);
    if ((currentLevel >= minLevel) && (abs(q - r) <= 3.0 * tol)) {
        return q;
    } else if (currentLevel >= maxLevel) {
        return q;
    } else {
        ++currentLevel;
        return (trap(f, a, (a + b) / 2.0, tol / 2, currentLevel) + trap(f, (a + b) / 2.0, b, tol / 2, currentLevel));
    }
}

您可以添加一个辅助函数,这样您就不必指定 currentLevel:

 double integrate(double (*f)(double x), double a, double b, double tol)
 {
     return trap(f, a, b, tol, 1);
 }

如果我将其称为integrate(square, 0, 2, 0.01),我会得到 2.6875 的答案,这意味着您需要更低的容差才能收敛到8/3 = 2.6666...7 的正确结果。您可以使用Simpson's method 的错误术语来检查确切的错误范围。

【讨论】:

  • 我明白了。计算间隔时出现愚蠢的数学错误。为什么增加全局变量不好?似乎它会产生相同的效果。非常感谢您的帮助。
  • 我看到使用辅助函数这样我不需要 currentLevel 作为全局变量就可以了。它现在收敛到正确的值,但是,我不明白为什么这会有所帮助。
  • 我现在明白为什么我不希望 currentLevel 作为全局变量了。将其作为全局变量完全违背了自适应算法的概念目的。我需要它依赖于函数递归的当前级别。谢谢。
  • @kienjakenobi:是的,这正是原因。在更复杂的场景中,如果你把它作为一个全局变量,那么这个方案为什么会失败会变得更加明显。祝你未来的 C++ 编程好运!
猜你喜欢
  • 1970-01-01
  • 2019-08-18
  • 2017-03-22
  • 1970-01-01
  • 2019-04-26
  • 2010-12-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多