2023-06-18《计算方法》- 陈丽娟 - 方程的近似解法.md

发布时间 2023-06-18 16:55:37作者: XNEF

2023-06-18《计算方法》- 陈丽娟 - 方程的近似解法

在这里我先跳过了曲线拟合这一部分,这是因为我主要想快速切入到数值微积分部分,因此直接直接来到了方程的近似解部分。

一、二分法

二分法对如下问题进行求解:
在区间上连续,且,求使得.

这里给出一个可调整的二分法算法:

  1. 给定参数, ;
  2. 在区间内取一点, 可知;
  3. 计算, 若(), 则是解;
  4. , 则令, 否则;
  5. 回到第2步。

这个算法含有可调节参数, 其取值对逼近速度将产生影响,当就是二分法。另外这里的二分法适用于一维情况(多维情况怎么做尚不清楚,没有搜索到,如知道请告知,谢谢

下面给出这个算法的对应程序(黄金比例):

  1. % r分法求解函数f在ab上的根,精度为epsilon 
  2. function [xs xslog] = BiSection(f, a, b, r, epsilon) 
  3. xslog = []; 
  4. fa = feval(f, a); 
  5. fb = feval(f, b); 
  6. if abs(fa) <= epsilon 
  7. xs = a; 
  8. elseif abs(fb) <= epsilon 
  9. xs = b; 
  10. elseif fa * fb > 0 
  11. xs = Inf; 
  12. else 
  13. while fa * fb < 0 
  14. c = r*a + (1-r) * b; 
  15. xslog = [xslog c]; 
  16. fc = feval(f, c); 
  17. if abs(fc) <= epsilon 
  18. xs = c; 
  19. break 
  20. else 
  21. if fa * fc < 0 
  22. b = c; 
  23. else 
  24. a = c; 
  25. end 
  26. end 
  27. end 
  28. end 
  29. end 

对应的测试用例

  1. % 二分法测试用例 
  2. f = @(x) sin(x); 
  3. r = 0.618; 
  4. epsilon = 1e-8; 
  5.  
  6.  
  7. %f(a) f(b) > 0 
  8. a = 0.1; 
  9. b = pi/2; 
  10. [xs xslog] = BiSection(f, a, b, r, epsilon); 
  11.  
  12. %f(a) = 0 
  13. a = 0; 
  14. b = pi/2; 
  15. [xs xslog] = BiSection(f, a, b, r, epsilon); 
  16.  
  17. %f(b) = 0 
  18. a = 0.1; 
  19. b = pi; 
  20. [xs xslog] = BiSection(f, a, b, r, epsilon); 
  21.  
  22. % f(a)f(b)<0 
  23. a = 0.3; 
  24. b = 5; 
  25. [xs xslog] = BiSection(f, a, b, r, epsilon); 
  26. r = 0.5; 
  27. [xs1 xslog1] = BiSection(f, a, b, r, epsilon); 
  28. r = 0.7; 
  29. [xs2 xslog2] = BiSection(f, a, b, r, epsilon); 
  30. plot(xslog) 
  31. hold on 
  32. plot(xslog1) 
  33. hold on 
  34. plot(xslog2) 
  35. legend(["0.3" "0.5" "0.7"]) 

enter description here
enter description here

二、迭代法基本思想

对于求解,该式等价于


, 得到迭代格式

收敛, 则有

,也即是.
不动点迭代法对于很多零点(不动点)问题都行之有效,但是基本的迭代格式要求满足一定的条件(非扩张映射),这部分可以参考不动点理论,这里给几个基本的不动点相关论文:
Xu H. Iterative Algorithms for Nonlinear Operators. Journal of the London Mathematical Society. 2002;66:240-56. doi: 10.1112/S0024610702003332.
Maingé P-E. Strong Convergence of Projected Subgradient Methods for Nonsmooth and Nonstrictly Convex Minimization. Set-Valued Analysis. 2008;16(7):899-912. doi: 10.1007/s11228-008-0102-z.

注:在构建迭代序列的时候,特别应该注意到构造的算子尽量满足非扩张性(1-Lipschitiz连续)

定理1
如果满足下列条件:
  1. 时,;
  2. 当任意时,存在, 使,
    则方程上有唯一的根, 且对任意的,有:
  3. 迭代公式收敛于;
  4. 有误差估计式;

上述定理的证明由拉格朗日定理和迭代格式立即可得。

书中的局部收敛性和收敛速度这里不做讨论。

三、牛顿法

对函数处做泰勒展开可得


可以得到近似的不动点迭代格式

上述形式即牛顿迭代法。注意到一开始我们是使用的泰勒展开得到的,而一阶泰勒展开仅在很小的邻域内有较好的近似结果,因此牛顿法仅适用于初始点在零点附近处使用。为了能够得到对任意点均能收敛的牛顿迭代法,可以使用牛顿下山法

其中取值为使得.
这里我们给出程序:

  1. % f目标函数, x0初始点,epsilon, 用于求导的h 
  2. function [xs, xslog] = NewtonDes(f, x0, epsilon, h, maxit) 
  3. xs = x0; 
  4. iter = 1; 
  5. xslog = []; 
  6. if abs(feval(f,x0)) <= epsilon 
  7.  
  8. else 
  9. while abs(feval(f,xs)) > epsilon 
  10. if iter > maxit 
  11. break 
  12. end 
  13. x0 = xs; 
  14. lambda = 1; 
  15. fx0 = feval(f,x0); 
  16. fxdiff = (feval(f,x0+h) - fx0)/ h; 
  17. xs = x0 - lambda * fx0 / fxdiff; 
  18. while abs(feval(f,xs)) > abs(fx0) 
  19. lambda = lambda / 2; 
  20. xs = x0 - lambda * fx0 / fxdiff; 
  21. end 
  22. xslog = [xslog xs]; 
  23. iter = iter + 1; 
  24. end 
  25. end 
  26. end 

例子

  1. f = @(x) 5 .* x.^3+x.^2-x+1; 
  2. epsilon = 1e-8; 
  3. x0 = 0.4; 
  4. h = 1e-4; 
  5. maxit = 1e3; 
  6. [xs, xslog] = NewtonDes(f, x0, epsilon, h, maxit) 

得到解为-0.7824。注意这里我们设置导数的计算间隔为, 当间隔取得很小的时候,上述程序会有数值稳定性问题:

  1. f = @(x) 5 .* x.^3+x.^2-x+1; 
  2. epsilon = 1e-8; 
  3. x0 = 0.4; 
  4. h = 1e-8; 
  5. maxit = 1e3; 
  6. [xs, xslog] = NewtonDes(f, x0, epsilon, h, maxit) 

通过断点,这个问题来自于

  1. fxdiff = (feval(f,x0+h) - fx0)/ h; 
  2. xs = x0 - lambda * fx0 / fxdiff; 

由于这个函数本身中间部分很平滑,导致了很大(2333), 然后又需要重新从2333开始通过lambda逼近到更好的解。然后又由于指数下降,导致最后几乎在一个非零解的地方不动。这个问题可以通过更换初始值得到缓解:

  1. f = @(x) 5 .* x.^3+x.^2-x+1; 
  2. epsilon = 1e-8; 
  3. x0 = -0.4; 
  4. h = 1e-8; 
  5. maxit = 1e3; 
  6. [xs, xslog] = NewtonDes(f, x0, epsilon, h, maxit) 

另外可以给出一个不重置的算法:

  1. % f目标函数, x0初始点,epsilon, 用于求导的h 
  2. function [xs, xslog] = NewtonDes(f, x0, epsilon, h, maxit) 
  3. xs = x0; 
  4. iter = 1; 
  5. xslog = []; 
  6. lambda = 1; 
  7. if abs(feval(f,x0)) <= epsilon 
  8.  
  9. else 
  10. while abs(feval(f,xs)) > epsilon 
  11. if iter > maxit 
  12. break 
  13. end 
  14. x0 = xs; 
  15. fx0 = feval(f,x0); 
  16. fxdiff = (feval(f,x0+h) - fx0)/ h; 
  17. xs = x0 - lambda * fx0 / fxdiff; 
  18. while abs(feval(f,xs)) > abs(fx0) 
  19. lambda = lambda / 2; 
  20. xs = x0 - lambda * fx0 / fxdiff; 
  21. end 
  22. xslog = [xslog xs]; 
  23. iter = iter + 1; 
  24. end 
  25. end 
  26. end 

这个算法也可以逼近解,但是同样会存在对某些初始值在导数间隔很小的时候不能逼近到解。书中并未给出如何解决这个问题,因此高精度的牛顿下山法我并未实现。(希望书后面的数值微积分中能有更好的处理导数的方法)