1. 程式人生 > >牛頓迭代法求根

牛頓迭代法求根

三次方根

(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 namespace
std; 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)=xma
2. 原函式的導函式: f'(x)=mxm-1f(x)=mxm1
3. 使用牛頓迭代公式 

可得xn+1=xnf(xn)f(xn)=xnxmnamxm1n

對於本題而言 可以看成解方程 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 誤差有點大。

不過可以通過調引數來調整

同樣的利用牛頓迭代法可以推導到一般情況,大家可以嘗試一下。