計算方法之非線性方程組求解
非線性方程求根數值解法
實驗目的
(1)通過對二分法與牛頓迭代法做程式設計練習和上機運算,進一步體會二分法和牛頓法的不同。
(2)編寫割線迭代法的程式,求非線性方程的解,並於牛頓迭代法作比較。
一、實驗內容
1、用牛頓迭代法求下列方程的根
(1) x^2-e^x=0
(2) xe^x-1=0
(3) lgx+x-2=0
2、二分法解以上問題
3、編寫割線法程式求解第一問的方程
實驗步驟、程式設計、實驗結果及分析
一、用牛頓迭代法求下列方程的根:
1.1實驗步驟:
以第一題為例,列舉實驗步驟
令 f(x)= x^2-e^x
求得f’(x)=2×x -e^x
xk+1
迭代計算即可
1.2程式設計:
(1) x^2-e^x=0
#include <bits/stdc++.h>
using namespace std;
int main()
{
double x0,x;
x=1;
do
{
x0=x;
double fx=x*x-exp(x);
double fx2=x*2-exp(x);
x=x0-(fx/fx2);
}while(fabs(x-x0)>=1e-5);
cout<<x0<<endl;
return 0;
}
(2) xe^x-1=0
#include <bits/stdc++.h>
using namespace std;
int main()
{
double x0,x;
x=1;
do
{
x0=x;
double fx=x*exp(x)-1;
double fx2=x*exp(x)+exp(x);
x=x0-(fx/fx2);
}while(fabs(x-x0)>=1e-5);
cout<<x0<<endl;
return 0;
}
分析:
通過牛頓迭代法,求出f(x)的導數,根據xk+1=xk-f(x)/f’(x)
進行迭代,通過實驗發現我們只需要通過5次迭代就可以求出答案
(3) lgx+x-2=0
#include <bits/stdc++.h>
using namespace std;
int main()
{
double x0,x;
x=1;
do
{
x0=x;
double fx=log10(x)+x-2;
double fx2=1/x+1;
x=x0-(fx/fx2);
}while(fabs(x-x0)>=1e-5);
cout<<x0<<endl;
return 0;
}
分析:
通過牛頓迭代法,求出f(x)的導數,根據xk+1=xk-f(x)/f’(x)
進行迭代,通過實驗發現我們只需要通過9次迭代就可以求出答案
二、二分法求方程的根
2.1實驗步驟
1)我們給定一個初始的範圍,這個範圍要求在區間內函式單調並且有且僅有一個根
2)通過判斷 mid=(r+l)/2 是不是滿足f(mid)=0的條件,如果不滿足就縮小範圍(l,mid) 或者是(mid,r)
3)當l,r的區間長度小於一個很小的數eps的時候,那麼我們就相當於求出了方程的根
2.2程式設計
(1) x^2-e^x=0
#include<bits/stdc++.h>
#define eps 1e-5
using namespace std;
bool check(double k)
{
if(k*k-exp(k)>1e-4)return true;
else return false;
}
int main()
{
double l=-1,r=0;
int cnt=0;
while(r-l>eps)
{
double mid=l+(r-l)/2;
//cout<<mid<<endl;
cnt++;
if(check(mid))
{
l=mid;
}
else r=mid;
}
printf("cnt=%d\n",cnt);
printf("answer=%.5lf\n",r);
return 0;
}
分析:二分法的迭代次數,顯然與要求的精度和其實兩數的範圍有關
2)xe^x-1=0
#include<bits/stdc++.h>
#define eps 1e-4
using namespace std;
bool check(double k)
{
if(k*exp(k)-1>1e-4)return true;
else return false;
}
int main()
{
double l=-1,r=1;
int cnt=0;
while(r-l>eps)
{
double mid=l+(r-l)/2;
//cout<<mid<<endl;
cnt++;
if(check(mid))
{
r=mid;
}
else l=mid;
}
printf("cnt=%d\n",cnt);
printf("answer=%.7lf\n",r);
return 0;
}
3)lgx+x-2=0
#include<bits/stdc++.h>
#define eps 1e-4
using namespace std;
bool check(double k)
{
if(log10(k)+k-2>1e-4)return true;
else return false;
}
int main()
{
double l=-2,r=2;
int cnt=0;
while(r-l>eps)
{
double mid=l+(r-l)/2;
//cout<<mid<<endl;
cnt++;
if(check(mid))
{
r=mid;
}
else l=mid;
}
printf("cnt=%d\n",cnt);
printf("answer=%.7lf\n",r);
return 0;
}
三、割線法求第一問
3.1實驗步驟
1)令 f(x)= x^2-e^x
2)x_(k+1)=x_k-f(x_k )/((f(x_k )-〖f(x〗(k-1) ) )*(x_k-x(k-1))
3)迭代計算即可
3.2程式設計
#include <bits/stdc++.h>
using namespace std;
int main()
{
double xk,x1,xk2;
xk2=1;
xk=-1;
do
{
x1=xk2;
double fx=xk*xk-exp(xk);
double fx2=xk2*xk2-exp(xk2);
xk2=xk2-(fx2/(fx2-fx))*(xk2-xk);
xk=x1;
}while(fabs(xk2-xk)>=1e-5);
cout<<xk<<endl;
return 0;
}
使用割線法求解,根據公式x_(k+1)=x_k-f(x_k )/((f(x_k )-〖f(x〗(k-1) ) )*(x_k-x(k-1)),迭代次數與初始的設定值有關,當初始值設定為1和-1時,我們需要迭代7次,當初始值設為-0.5和-1時,迭代6次,因此我們可以知道,兩個初始值儘可能在方程的解旁時,能有效的減少迭代次數。
總結
牛頓迭代法具有收斂速度快,能求重根等有點,但是每迭代一步,都要計算函式的導數值,計算量很大,尤其是當函式的結構比較複雜或者函式不可導的時候,就很難使用牛頓迭代法,為了克服這種缺點,常常採用離散牛頓法,與牛頓法相比,它避免了求函式f(x)的導數,但需要兩個初始值,且這兩個初始值儘量取在方程的根的附近,其收斂速度一般比牛頓法慢。但比現行收斂要快。而二分法通過不斷二分縮小區間,二分的迭代次數與要求的精度和設定的起始資料有關。