|
[导读] 前面刚转了一篇文章提到了牛顿-拉夫逊(拉弗森)(Newton-Raphson method)方法,感觉这个数学方法很有必要相对深入写一篇文章来总结分享印证一下自己的理解。这是写本文的由来,如果发现文章中有错误之处,请留言交流讨论。2 Q$ c: E9 L7 o9 n/ ~7 N 2 _% |! s+ H6 J* o: ^1 W
所以,牛顿迭代法(简写)就是一种近似求解实数域与复数域求解方程的数学方法。那么这个方法是具体是什么原理呢? 直接看数学公式描述如何迭代不直观,先来看动图就很容易理解牛顿迭代法为什么叫迭代法以及怎样迭代的: 牛顿迭代法是原理是根据一个初始点在该点做切线,切线与X轴相交得出下一个迭代点的坐标,再在处做切线,依次类推,直到求得满足精度的近似解为止。
由前面描述知道,牛顿迭代法是用来近似求解方程的,这里有两个点需要说明:+ g. c" h, C/ z, Q9 t
来看看,数学上如何描述的?
来简单推一推上面公式的由来,直线函数方程为:
2 P* Q) m& `6 M! h 如何编码呢? 由于牛顿迭代法主要目的是解方程,当然也有可能用于某一个数学函数求极值,所以无法写出通用的代码,这里仅仅给出一个编代码的思路。相信掌握了思路,对于各种实际应用应该能很快的写出符合实际应用的代码。 假定一函数为
其波形图如下:
其一阶导数为:
那么对于该函数的根:
从图上大致可以知道有两个根,如果直接解方程,则很难求出其根,可以编个代码试试: #include <stdio.h>, ^; G: \8 u0 |) s( L7 P: Q* V% n9 W6 X7 H#include <math.h> #include <stdlib.h> 1 {3 m7 ?% L( }( h6 H, d /*假定待求根函数如下*/% l5 Y, t/ x s/ u' J) w #define F(x) (2*(x)*(x)-10*cos(x)+(x)-80)# [2 F" a* o3 b5 I /*其一阶导数为*/ #define DF(x) (4*(x)+10*sin(x)+1) 5 n" z# x0 |( B float newton_rooting(float x0,float precision,float min_deltax,int max_iterations) { float xn,xn1,fn,fn1,dfn; float deltax; int step = 0;. |: D: m/ x- k xn = x0; xn1 = x0; do{# S+ a9 d' W( e: L+ t3 ~/ _+ _ xn = xn1; fn = F(xn); dfn = DF(xn); /*判0*/' b# b, B; y: X( q% o if( fabs(dfn) <1e-6 ) { if( fabs(fn)>precision ) return NAN;7 p, {( B0 m9 P$ E' ]2 Q2 }0 C else return fn;; {" _9 w. a8 o }, h; I5 ^. V* H& W+ j7 h 7 F' k/ M0 G* F xn1 = xn - fn/dfn;. f! f/ f- z9 g0 c0 z fn1 = F(xn1);% t/ Y: I6 V& A, E) K1 E' O deltax = fabs(xn1-xn);9 a, u, B3 b3 U! s3 m3 a ' ^! S7 _) p, A: R$ [( Q) a step++; if( step>max_iterations )5 Q( X' O, {/ ?! o r; ], P X { if( fabs(fn1)<precision )% f- m, v- ~) H* q+ a) U. H* w return xn; else( [0 ?& K# S# @/ w return NAN;: m3 P& o9 P3 q1 V' W } }3 [0 B7 w0 v, J" m while( fabs(fn1)>precision || deltax>min_deltax ); ! o; m2 |; d5 `( V return xn1; }7 Y4 V9 y* |& g: k/ \ void main() {& C8 }! m( D0 K5 s3 T float root_guess = 23.0f; float precision = 0.00001f;# `) |% l$ M! B6 h5 g float min_deltax = 0.001f; float root; int step = 7;9 U% }- | X) _; r/ @ root = newton_rooting( root_guess,precision,min_deltax,step ); printf("根为: %f,函数值为:%f\n", root,F(root)); ) W4 ?4 S6 Q* N! J# r! F* O! ` root_guess = -23;6 J1 r' {0 t. C- H O root = newton_rooting( root_guess,precision,min_deltax,step ); printf("根为: %f,函数值为:%f\n", root,F(root));/ i% M; ~: q: G }9 `5 B, P$ s4 [6 A 结果: 根为: 6.457232, 函数值为:0.0000046 z7 E J' ]: e" Y6 t( U根为: -6.894969,函数值为:-0.000008; [. M1 T+ F# l% X% B4 U+ T 函数值已经很接近于0了,如果还需要更为精确的值,则可以选择在此基础上进一步求解,比如利用二分法逼近。 需要注意些啥?
所以实际应用时,需要知道自己待求解模型的大致情况,在合理的加以调整。 有哪些应用?
牛顿迭代法在解决实际问题时,利用迭代求方程近似根的数学原理,在工程中有着很好的实用价值。比如求一个趋势的极值,传递函数参数辨识等都有广泛的实际应用。本文抛砖引玉,有可能文章也有很多错误疏漏的地方,如有不同看法或者发现错误,欢迎留言交流指正。 ; m, E8 d1 k# ~( F8 @4 [' c4 [# T) R" }; ^1 ^0 ]* [$ {( I |
| 大大的点赞,好厉害! |
微信公众号
手机版