不动点迭代算法

你说的曾经没有我的故事 提交于 2020-03-05 22:37:10

今天有个小朋友向我提出了一个「了不起」的问题。

一个有趣的现象

打开一个没有 Bug 的计算器,任意输入一个数值 \(x\),然后找到函数 \(sin(x)\) 或者 \(cos(x)\) ,连续点击这个函数若干次,你会发现一个有趣的现象:无论初始的 \(x\) 为多少,最后的值总是接近某一个数值(这些数值在某个精度范围内是相等的)。\(sin(x)\) 最后总为 \(0\)\(cos(x)​\) 最后为 0.73 或者 0.99 (取决于你的计算器是否开启弧度制)。

从数学的角度来看,实际上就是:定义 \(f^1(x) = f(x), f^2(x)=f(f(x)), f^{n}(x)=f(f(f(...f(x))))\)\(n\)\(f\) 进行复合函数运算,求 \(\lim\limits_{n \rightarrow \infty} f^{n}(x)\)

显然,这道证明题我不会😅。

万能的搜索引擎

虽然我不会证明,但是找一下是什么知识点还是挺简单的。查了一圈回来,发现这其实是「数值分析」中的 不动点方程 。上述证明题,\(\lim\limits_{n \rightarrow \infty} f^{n}(x)\) 的值实际上是 \(x = f(x)​\) 的根。这个方程用「零点定理」,写一个 while-loop 就出来了,所以就不说了。

算了,还是说一下吧,反正闲着也是闲着。设 \(g(x) = x - \cos(x)​\),显然 \(g(0) \cdot g(1) < 0​\)\(g(x)​\) 为增函数,因此在 \((0,1)​\) 上有 1 个零点。

#include <iostream>
#include <cmath>
using namespace std;
double func(double x)
{
    return x - cos(x);
}
int main()
{
    const double eps = 1e-8;
    double l = 0, r = 1;
    while ((r - l) >= eps)
    {
        double mid = (l + r) / 2;
        func(mid) > 0 ? (r = mid) : (l = mid);
    }
    printf("%.8lf %.8lf\n", l, r);
}

不动点迭代算法

这是扩展阅读部分,因为这篇文章看起来篇幅不太够,所以就凑点字数,反正看 blog 的人大多数都是一些「无聊的人」O(∩_∩)O 。

不动点迭代 (Fixed Point Iteration) ,用于求解某些非线性函数 \(f(x)​\) 的零点,也就是解方程 \(f(x) = 0​\) 。那么这个「不动点迭代算法」到底有什么用呢?

比如我想求 \(f(x) = 1 + 0.5 \sin{x} - x​\) 的根,那么可以进行如下变换:
\[ f(x) = 0 \quad \Rightarrow \quad x = 1+0.5\sin{x} \]
然后令 \(g(x) = 1+0.5 \sin {x}\) ,对 \(x_{i+1} = g(x_i)\) 执行迭代若干次,就可以得到原方程的根 \(x_n\)

有这个「不动点迭代」法,求根就可以简单一点(虽然比「二分法」没简单多少😅)。

double func(double x)
{
    return 1 + 0.5 * sin(x);
}
int main()
{
    srand(time(NULL));
    double x = rand();
    for (int i = 0; i < 10; i++)
        x = func(x);
    printf("%.10lf", x);
}

但这个算法其实对于 \(g(x)\) 来说是有条件的,并不是所有的方程都适用。如果对于方程 \(x = 2x^3-1, g(x)=2x^3-1\) 执行上面的算法,我们是得不到正确的答案 \(x=1\) 的。

Aside
设迭代函数 \(g(x)\)\([a,b]\) 上连续,且满足:

  • \(x \in [a,b]\) 时,\(a \le g(x) \le b\)
  • 存在一正数 \(L\) 满足 \(0 < L < 1\),且 \(\forall{x} \in [a,b]\) 均有 \(|g^{'}(x)| \le L\)

则方程 \(x = g(x)\)\([a,b]\) 上有唯一解 \(x_n\) 。对于任意的初值 \(x_0 \in [a,b]\) ,均可通过 \(x_{i+1} = g(x_i)\) 迭代求得 \(x_n\)

详细的证明请看这里

总结

实际上我并没有解决这个小朋友的疑问(因为👴也🔈懂怎么证明),但是至少我又水了一篇 blog,打发了两个小时的无聊时间。唉,什么时候才动手搞毕业设计呢,真是有够堕落的。

众所周知,百度是一家大型广告公关公司,附带高质量的站内搜索引擎🔍,但有一说一,百度文库确实挺好用的😂,特别是找课件看,找期末题库。

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!