牛頓迭代法(簡(jiǎn)寫(xiě))就是一種近似求解實(shí)數(shù)域與復(fù)數(shù)域求解方程的數(shù)學(xué)方法。那么這個(gè)方法是具體是什么原理呢?本篇文章將會(huì)介紹如何用牛頓迭代法(Newton's method for finding roots)求方程的近似解,該方法于17世紀(jì)由牛頓提出。
具體的任務(wù)是,對(duì)于在[a,b]上連續(xù)且單調(diào)的函數(shù)f(x),求方程f(x)=0的近似解。
牛頓迭代如何迭代?
直接看數(shù)學(xué)公式描述如何迭代不直觀,先來(lái)看動(dòng)圖就很容易理解牛頓迭代法為什么叫迭代法以及怎樣迭代的:
牛頓迭代法是原理是根據(jù)一個(gè)初始點(diǎn)(x0,f(x0))在該點(diǎn)做切線,切線與X軸相交得出下一個(gè)迭代點(diǎn)x1的坐標(biāo),再在(x1,f(x1))處做切線,依次類推,直到求得滿足精度的近似解為止。
由前面描述知道,牛頓迭代法是用來(lái)近似求解方程的,這里有兩個(gè)點(diǎn)需要說(shuō)明:
(1)為啥要近似求解?很多方程可能無(wú)法直接求取其解
(2)迭代法非常適合計(jì)算機(jī)編程實(shí)現(xiàn),實(shí)際上計(jì)算機(jī)編程對(duì)于牛頓迭代法廣為應(yīng)用
來(lái)看看,數(shù)學(xué)上如何描述的?
其中為函數(shù)在處的一階導(dǎo)數(shù),也就是該點(diǎn)的切線。
來(lái)簡(jiǎn)單推一推上面公式的由來(lái),直線函數(shù)方程為:
知道一個(gè)直線的一個(gè)坐標(biāo)點(diǎn)以及斜率則該直線的方程就很容易可以得知:
那么該直線與x軸的交點(diǎn),就是也即等式x的解:
啥時(shí)候停止迭代呢?
1. 計(jì)算出;
2. 給出一個(gè)初始假定根值,利用上面迭代式子進(jìn)行迭代
;
3. 計(jì)算絕對(duì)相對(duì)迭代近似誤差
4. 將絕對(duì)相對(duì)近似誤差與預(yù)定的相對(duì)誤差容限進(jìn)行比較。 如果,則迭代步驟2,否則停止算法。 另外,檢查迭代次數(shù)是否已超過(guò)允許的最大迭代次數(shù)。 如果是這樣,則需要終止算法并退出。另一個(gè)終止條件是:
$$|f(x_{i+1})|如何編碼呢?
由于牛頓迭代法主要目的是解方程,當(dāng)然也有可能用于某一個(gè)數(shù)學(xué)函數(shù)求極值,所以無(wú)法寫(xiě)出通用的代碼,這里僅僅給出一個(gè)編代碼的思路。相信掌握了思路,對(duì)于各種實(shí)際應(yīng)用應(yīng)該能很快的寫(xiě)出符合實(shí)際應(yīng)用的代碼。
假定一函數(shù)為:
其波形圖如下:
其一階導(dǎo)數(shù)為:
那么對(duì)于該函數(shù)的根:
從圖上大致可以知道有兩個(gè)根,如果直接解方程,則很難求出其根,可以編個(gè)代碼試試:
#include <stdio.h> #include <math.h> #include <stdlib.h> /*假定待求根函數(shù)如下*/ #define F(x) (2*(x)*(x)-10*cos(x)+(x)-80) /*其一階導(dǎo)數(shù)為*/ #define DF(x) (4*(x)+10*sin(x)+1) float newton_rooting(float x0,float precision,float min_deltax,int max_iterations) { float xn,xn1,fn,fn1,dfn; float deltax; int step = 0; xn = x0; xn1 = x0; do{ xn = xn1; fn = F(xn); dfn = DF(xn); /*判0*/ if( fabs(dfn) <1e-6 ) { if( fabs(fn)>precision ) return NAN; else return fn; } xn1 = xn - fn/dfn; fn1 = F(xn1); deltax = fabs(xn1-xn); step++; if( step>max_iterations ) { if( fabs(fn1)<precision ) return xn; else return NAN; } } while( fabs(fn1)>precision || deltax>min_deltax ); return xn1; } void main() { float root_guess = 23.0f; float precision = 0.00001f; float min_deltax = 0.001f; float root; int step = 7; root = newton_rooting( root_guess,precision,min_deltax,step ); printf("根為: %f,函數(shù)值為:%f\n", root,F(root)); root_guess = -23; root = newton_rooting( root_guess,precision,min_deltax,step ); printf("根為: %f,函數(shù)值為:%f\n", root,F(root)); }
結(jié)果:
根為: 6.457232, 函數(shù)值為:0.000004 根為: -6.894969,函數(shù)值為:-0.000008
函數(shù)值已經(jīng)很接近于0了,如果還需要更為精確的值,則可以選擇在此基礎(chǔ)上進(jìn)一步求解,比如利用二分法逼近。
需要注意些啥?
求斜率可能為0,如為0時(shí),則可能找到了函數(shù)的極值,比如:
如果選擇的初始猜測(cè)根的接近方程f(x)=0中函數(shù)f(x)的拐點(diǎn) ,Newton-Raphson方法可能開(kāi)始偏離根。 然后,它可能會(huì)又收斂回到根。例如:
如果選擇的初值不合適,可能會(huì)跳掉一些根,比如:
所以實(shí)際應(yīng)用時(shí),需要知道自己待求解模型的大致情況,在合理的加以調(diào)整。
有哪些應(yīng)用?
比如知道某系統(tǒng)的傳遞函數(shù),待求解其中的參數(shù),可以將上述方法推而廣之,求解多維變量方程組,求導(dǎo)就變成求偏導(dǎo)了
又比如設(shè)計(jì)一電路測(cè)量某物質(zhì)的阻抗
....
總結(jié)一下
牛頓迭代法在解決實(shí)際問(wèn)題時(shí),利用迭代求方程近似根的數(shù)學(xué)原理,在工程中有著很好的實(shí)用價(jià)值。比如求一個(gè)趨勢(shì)的極值,傳遞函數(shù)參數(shù)辨識(shí)等都有廣泛的實(shí)際應(yīng)用。
C語(yǔ)言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競(jìng)賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:
一點(diǎn)編程也不會(huì)寫(xiě)的:零基礎(chǔ)C語(yǔ)言學(xué)練課程
解決困擾你多年的C語(yǔ)言疑難雜癥特性的C語(yǔ)言進(jìn)階課程
從零到寫(xiě)出一個(gè)爬蟲(chóng)的Python編程課程
只會(huì)語(yǔ)法寫(xiě)不出代碼?手把手帶你寫(xiě)100個(gè)編程真題的編程百練課程
信息學(xué)奧賽或C++選手的 必學(xué)C++課程
藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競(jìng)賽課入門課程
手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程