非线性方程求根数值解法 
 实验目的 
 (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=xk-f(x)/f’(x) 
 迭代计算即可 
 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)的导数,但需要两个初始值,且这两个初始值尽量取在方程的根的附近,其收敛速度一般比牛顿法慢。但比现行收敛要快。而二分法通过不断二分缩小区间,二分的迭代次数与要求的精度和设置的起始数据有关。

京公网安备 11010502036488号