• 博客园logo
  • 会员
  • 众包
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • HarmonyOS
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录

NEFCODER

  • 博客园
  • 联系
  • 订阅
  • 管理

公告

View Post

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

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

Matlab计算方法二分法迭代法牛顿法

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

一、二分法

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

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

  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 

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

posted on 2023-06-18 16:43  XNEF  阅读(151)  评论(0)    收藏  举报

刷新页面返回顶部
 
博客园  ©  2004-2025
浙公网安备 33010602011771号 浙ICP备2021040463号-3