【问题标题】:Simple iteration algorithm简单的迭代算法
【发布时间】:2011-11-01 13:29:27
【问题描述】:

如果给定一个非线性方程系数数组和某个范围,我们如何在给定范围内找到该方程的根?

例如:等式是

所以系数数组将是 a 的数组。假设方程是

那么系数数组就是{ 1, -5, -9, 16 }。

正如谷歌所说,首先我们需要将给定的函数(实际上是方程)变形为其他函数。例如。如果给定的方程是y = f(x),我们应该定义其他函数,x = g(x),然后执行算法:

while (fabs(f(x)) > etha)
  x = g(x);

找出根。

问题是:如何使用系数数组和仅给出的范围来定义g(x)?

问题是:当我这样定义g(x)时

或

对于给定的方程,x 的任何起始值都会引导我找到第二个方程的根。没有人会给我另外两个(根是{ -2.5, 1.18, 6.05 },我的代码只给1.18)。

我的代码是这样的:

float a[] = { 1.f, -5.f, -9.f, 16.f }, etha = 0.001f;

float f(float x)
{
    return (a[0] * x * x * x) + (a[1] * x * x) + (a[2] * x) + a[3];
}

float phi(float x)
{
    return (a[3] * -1.f) / ((a[0] * x * x) + (a[1] * x) + a[2]);
}

float iterationMethod(float a, float b)
{
    float x = (a + b) / 2.f;

    while (fabs(f(x)) > etha)
    {
        x = phi(x);
    }

    return x;
}

因此,调用iterationMethod() 传递范围{ -3, 0 }、{ 0, 3 } 和{ 3, 10 } 将提供三次1.18 号码。

我哪里错了,我应该如何做才能让它正常工作?

UPD1:我不需要任何第三方库。

UPD2:我需要“简单迭代”算法。

【问题讨论】:

  • Equation Solvers for C++ 的冗长重复
  • 更新问题:只需要手工制作的“简单迭代”方法。没有任何第三方库。只是手工制作的一小段代码。
  • 数值算法可能会有很大差异,具体取决于您使用的函数。你对输入函数了解多少?是多项式吗?它们是可区分的吗?一次?两次?
  • @Ernest Friedman-Hill: ???我看到的唯一相似之处是两者都在询问方程式..:/

标签: c++ c algorithm math


【解决方案1】:

更传统的求根算法之一是Newton's method。迭代步骤涉及找到函数的一阶逼近的根

所以如果我们有一个函数'f'并且在一个点x0,线性一阶近似将是

f_(x) = f'(x0)*(x - x0) + f(x0)

而对应的近似根x'是

x' = phi(x0) = x0 - f(x0)/f'(x0)

(请注意,您需要方便地使用导数函数,但对于多项式应该很容易获得它)


牛顿方法的优点是易于实现,而且通常非常快。坏事是它有时表现不佳:该方法在具有 f'(x) = 0 的点上失败,并且某些函数中的某些输入可能会发散(因此您需要检查并在需要时重新启动)。

【讨论】:

    【解决方案2】:

    您在评论中发布的link 解释了为什么您无法使用此算法找到所有根 - 只有当 |phi'(x)| < 1 围绕根时它才会收敛到根。多项式的任何根都不是这种情况。对于大多数起点,迭代最终会围绕中间根反弹,并最终意外接近它;几乎可以肯定,无论从哪里开始,它都不会足够接近其他根源。

    要找到所有三个根,您需要一个更稳定的算法,例如 Newton's method(在您链接到的 tutorial 中也有描述)。这也是一种迭代方法;您可以使用迭代 x -> x - f(x)/f'(x) 找到 f(x) 的根。这仍然不能保证收敛,但收敛条件要宽松得多。对于您的多项式,它可能看起来有点像这样:

    #include <iostream>
    #include <cmath>
    
    float a[] = { 1.f, -5.f, -9.f, 16.f }, etha = 0.001f;
    
    float f(float x)
    {
        return (a[0] * x * x * x) + (a[1] * x * x) + (a[2] * x) + a[3];
    }
    
    float df(float x)
    {
        return (3 * a[0] * x * x) + (2 * a[1] * x) + a[2];
    }
    
    float newtonMethod(float a, float b)
    {
        float x = (a + b) / 2.f;
        while (fabs(f(x)) > etha)
        {
            x -= f(x)/df(x);
        }
    
        return x;
    }
    
    int main()
    {
        std::cout << newtonMethod(-5,0) << '\n'; // prints -2.2341
        std::cout << newtonMethod(0,5) << '\n';  // prints  1.18367
        std::cout << newtonMethod(5,10) << '\n'; // prints  6.05043
    }
    

    还有很多其他的求根算法; here 是一个开始学习的好地方。

    【讨论】:

      猜你喜欢
      • 2010-10-02
      • 1970-01-01
      • 2011-05-25
      • 2023-04-01
      • 1970-01-01
      • 2014-10-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多