1. 程式人生 > >二分法求取方程根

二分法求取方程根

問題背景:本次我們來求取 f(x) = -2x^3 + 5x^2 + 9,這個函式,在給定區間[2, 4]上的零點。

解決方法:二分法

程式語言:c++、python

說明:這裡將分別使用兩種程式語言和3種二分法的終止條件來完成二分的求解。

 

函式影象:

 

二分的終止條件:

1.區間小於某標準值

2.迴圈次數

3.真實誤差小於某值 |(Xnew - Xold) / Xnew| * 100%

 

流程圖:(偷個懶我這裡之畫一個)

 

 

c++篇

1.迴圈次數

//憑藉迴圈次數來終止二分

#include <iostream>
#include <cstdio>

using namespace std;

const int maxn = 9999;

double f(double x)
{
    return -2 * x * x * x + 5 * x * x + 9;
}

int main()
{
    double a = 2;         //卡取兩個端點值
    double b = 4;
    double mid;


    if (f(a) > 0)         //區間增函式
    {
        for (int i = 0; i <= maxn; i++)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0) a = mid;
            else b = mid;

        }
    }
    else                  //區間減函式
    {
        for (int i = 0; i <= maxn; i++)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0) b = mid;
            else a = mid;

        }
    }


    printf("f(%.3lf) = %.3lf\n", mid, f(mid));
    return 0;
}

2.區間小於某標準值

//區間小於某值來終止二分

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const double board = 1e-2;

double f(double x)
{
    return -2 * x * x * x + 5 * x * x + 9;
}

int main()
{
    double a = 2;         //卡取兩個端點值
    double b = 4;
    double mid;


    if (f(a) > 0)         //區間增函式
    {
        while (fabs(a - b) >= board)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0) a = mid;
            else b = mid;

        }
    }
    else                  //區間減函式
    {
        while (fabs(a - b) >= board)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0) b = mid;
            else a = mid;

        }
    }


    printf("f(%.3lf) = %.3lf\n", mid, f(mid));
    return 0;
}

3.真實誤差小於某值

//真實誤差小於某值來終止二分

#include <iostream>
#include <cstdio>
#include <cmath>

#define     INF     0x3f3f3f3f

using namespace std;

const double rate = 1e-2;

double f(double x)
{
    return -2 * x * x * x + 5 * x * x + 9;
}

int main()
{
    double a = 2;    //卡取兩個端點值
    double b = 4;
    double mid, r = INF;

    if (f(a) > 0)    //區間增函式
    {
        while (r > rate)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0)
            {
                r = fabs((mid - a) / a);
                a = mid;
            }
            else
            {
                r = fabs((mid - b) / b);
                b = mid;
            }

        }
    }
    else   //區間減函式
    {
        while (r > rate)
        {
            mid = (a + b) / 2;

            if (f(mid) == 0) break;

            if (f(mid) > 0)
            {
                r = fabs((mid - b) / b);
                b = mid;
            }
            else
            {
                r = fabs((mid - a) / a);
                a = mid;
            }

        }
    }


    printf("f(%.3lf) = %.3lf\n", mid, f(mid));
    return 0;
}

 

python篇

1.迴圈次數

# -*- coding: utf-8 -*-

#最大迴圈次數
maxn = 9999

#定義函式f(x)
def f(x):
    return -2.0 * x**3 + 5.0 * x**2 + 9.0

#規定兩區間端點
a = 2.0
b = 4.0

#進行二分
if f(a) > 0 :
    for i in range(maxn) :
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : a = mid
        else : b = mid
else :
    for i in range(maxn) : 
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : b = mid
        else : a = mid
 
#輸出結果       
print("f(%.3lf) = %.3lf\n" %(mid, f(mid)))
            

2.區間小於某標準值

# -*- coding: utf-8 -*-


import math

#定義邊界
board = 1e-2

#定義函式f(x)
def f(x):
    return -2.0 * x**3 + 5.0 * x**2 + 9.0

#規定兩區間端點
a = 2.0
b = 4.0

#進行二分
if f(a) > 0 :
    while math.fabs(a - b) >= board :
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : a = mid
        else : b = mid
else :
    while math.fabs(a - b) >= board : 
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : b = mid
        else : a = mid
 
#輸出結果       
print("f(%.3lf) = %.3lf\n" %(mid, f(mid)))
            

3.真實誤差小於某值

# -*- coding: utf-8 -*-


import math

#定義誤差率,與最大值
rate = 1e-2
INF = 0x3f3f3f3f

#定義函式f(x)
def f(x):
    return -2.0 * x**3 + 5.0 * x**2 + 9.0

#規定兩區間端點
a = 2.0
b = 4.0

r = INF

#進行二分
if f(a) > 0 :
    while r > rate :
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : 
            r = math.fabs((mid - a) / a)
            a = mid
        else : 
            r = math.fabs((mid - b) / b)
            b = mid
else :
    while r > rate : 
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : break
        
        if f(mid) > 0 : 
            r = math.fabs((mid - b) / b)
            b = mid
        else : 
            r = math.fabs((mid - a) / a)
            a = mid
 
#輸出結果       
print("f(%.3lf) = %.3lf\n" %(mid, f(mid)))
            

mid的變化趨勢:
為了使變化折線明顯這裡將區間段點值改為[1, 3.9]

影象生成程式碼:


# -*- coding: utf-8 -*-


import numpy as np
import matplotlib.pyplot as plt

plt.figure(1)
 
#最大迴圈次數
maxn = 9999
 
#定義函式f(x)
def f(x):
    return -2.0 * x**3 + 5.0 * x**2 + 9.0
 
#規定兩區間端點
a = 1.0
b = 3.9

#影象生成所需要的集合
m = []
n = []

scope = np.linspace(2, 4, 100)

 
#進行二分
if f(a) > 0 :
    for i in range(maxn) :
        
        mid = (a + b) / 2;
        
        m.append(mid)
        n.append(f(mid))
        
        if f(mid) == 0 : 
            break
        
        if f(mid) > 0 : 
            a = mid
        else : 
            b = mid
else :
    for i in range(maxn) : 
        
        mid = (a + b) / 2;
        
        if f(mid) == 0 : 
            break
        
        if f(mid) > 0 : 
            b = mid
        else : 
            a = mid
 
#輸出結果       
print("f(%.3lf) = %.3lf\n" %(mid, f(mid)))

#生成影象
plt.plot(m, n)
plt.show()
            

變化影象: