简单的迭代算法

时间:2011-11-01 13:29:28

标签: c++ c algorithm math

如果给出一系列非线性方程系数和一些范围,我们怎样才能在给定的范围内找到方程的根?

例如:等式

enter image description here

因此系数数组将是 a 的数组。让我们说等式是

enter image description here

然后系数数组为{ 1, -5, -9, 16 }

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

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

找出根。

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

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

enter image description here

enter image description here

对于给定的等式,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 :我完全需要“简单迭代”算法。

2 个答案:

答案 0 :(得分:4)

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

因此,如果我们有一个函数'f'并且位于x0点,则线性fisrt阶近似将是

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

和相应的近似根x'

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

(请注意,你需要使用派生函数,但是对于多项式来说它应该很容易获得)


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

答案 1 :(得分:3)

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

要查找所有三个根,您需要一个更稳定的算法,例如Newton's method(在您链接的tutorial中也会对此进行描述)。这也是一种迭代方法;您可以使用迭代f(x)找到x -> 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是开始学习的好地方。