牛頓迭代法求根
三次方根
(cube.pas/c/cpp)
【問題描述】
自從在第2題中老師們的工作積極性提高以來,以Fengzee為首的學生們苦不堪言,因為老師給他們留了太多的作業,有些作業甚至是幾乎無法完成的。這次,數學老師佈置下了10道開三次方的作業題,要求同學們筆算完成。Fengzee當然不會花時間做這種沒用的工作,他又沒有計算器。這樣的工作應當由電腦來完成,這就需要你程式設計序來解決。
你的輸入檔案中只含有一個實數n,是待開三次方的數字。你的任務是計算這個數的三次方根,並輸出在標準輸出檔案中。我們有演算法設計限制條件:這道題的主要運算過程,你必須自己在程式中設計,且評測時使用的編譯器已經去掉標頭檔案math.h,就是說,你不能使用這個標頭檔案中提供的一切函式。你只需要在檔案中寫入結果,不要加任何額外的文字。在滿足演算法設計限制條件的前提下,你的答案只需與標準答案相差不超過0.001,你即可得到全部的分數;而且你輸出的數字的小數位數不受限制(小數點保留六位)。
【輸入檔案】輸入檔案cube.in
輸入檔案中只含有一個實數n,是待開三次方的數字。
【輸出檔案】輸出檔案cube.out
數n的三次方根。
【樣例輸入】
9
【樣例輸出】
2.08008
【資料規模】
-10000<=n<=10000
一般實現
二分逼近法 (同學友愛的程式碼~)
#include <cstdio> #include <iostream> #include <algorithm> #define eps 1e-8 using namespacestd; double n; double fun(double mid) {return mid*mid*mid<n?1:0;} int main() { cin>>n; double l=0,r=n,mid; if(n<0) swap(l,r); while(r-l>eps){ //當精度未達到1e-8即10-8時,二分逼近 mid=(l+r)/2; if(fun(mid)) l=mid; //小的話 else r=mid; } printf("%.6f\n",r); }
然而我並沒有想到這一點
反而想起牛頓老人家了
我要在巨人的肩膀上幹事!!(其實是我蠢 =6=..)
沒錯 牛頓迭代法
定義 一種在實數域和複數域上近似求解方程的方法 --摘自百度
原理 不斷用(x,f(x))的切線來逼近方程的根
遞推公式 (證明過程可詳見百度)
加深理解可以參考 如何通俗易懂的講解牛頓迭代法
有了這個我們可以幹什麼呢。
當然是去解方程啦
求解步驟:
1. 原函式: f(x)=xm-af(x)=xm−a
2. 原函式的導函式: f'(x)=mxm-1f′(x)=mxm−1
3. 使用牛頓迭代公式
可得xn+1=xn−f(xn)f′(xn)=xn−xmn−amxm−1n
對於本題而言 可以看成解方程 x^3=a
代入公式可得 xn+1=(xn-x3-a)/3xn2
如此自定義一個函式就好了
注意:牛頓法只能逼近解,不能計算精確解。不過實際應用中,我們都不要求絕對精確的解,只要精度足夠高就好了 (所以此題我 wrong 了。)
#include <iostream> #include <cstdio> using namespace std; int mabs(int a) { if(a<0) a=-a; return a; } double sqrt(double c) { double err = 1e-7; //設立精度 double t = c; while (mabs(c - t*t*t) > err) t = 0.66667*t+c/(3.000*t*t); //三次方的遞推公式 return t; } int main() { int n; cin>>n; printf("%.6lf",sqrt(n)); return 0; }
輸入值 9 輸出值2.099878 誤差有點大。
不過可以通過調引數來調整
同樣的利用牛頓迭代法可以推導到一般情況,大家可以嘗試一下。