首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言三次方程求根:二分法實現與數值分析工程實踐

     編輯:關於C語言

三次方程 ax³ + bx² + cx + d = 0 求根是經典數值計算問題。雖然存在卡丹公式解析解,但二分法以其簡單、穩健、保證收斂的特性,成為工程實踐中尋找實根的首選。本文深度解析一個完整的 C++ 實現,展示如何結合導數極值定位根區間與二分法精確求根。

數學原理:三次多項式根的分佈

目標函數:f(x) = x³ - 3x² - 6x + 8

導數:f'(x) = 3x² - 6x - 6 = 0

極值點:x = (3 ± √21)/2 ≈ -0.791, 3.791

由羅爾定理,實根分佈於極值點分隔的區間:

  • (-∞, -0.791):單調遞增,一根
  • (-0.791, 3.791):單調遞減,一根
  • (3.791, +∞):單調遞增,一根

演算法流程

  1. 計算極值點:解導數得邊界
  2. 向外擴展區間:確保端點函數值異號
  3. 二分法求根:在各區間迭代至精度滿足

核心代碼解析

二分法函數

double bisection(double x, double y, double z) {
    double a = x, b = y, p;
    while ((b - a) / 2 >= z) {        // 區間寬度判斷
        p = (a + b) / 2;
        if (f(p) * f(b) <= 0)         // 根在 [p, b]
            a = p;
        else
            b = p;
    }
    return p;
}

收斂條件: (b-a)/2 < z 保證誤差 < z。

主流程:區間確定與求根

int main() {
    double a[5], tol;
    char filename[256];

    cout << "誤差容限: "; cin >> tol;
    cout << "輸出文件: "; cin >> filename;
    ofstream outfile(filename);

    // 極值點
    a[2] = (3 - sqrt(21)) / 2;  // ≈ -0.791
    a[3] = (3 + sqrt(21)) / 2;  // ≈ 3.791

    // 向外擴展確保異號
    a[1] = a[2]; a[4] = a[3];
    for (int i=1; ; i++) {
        if (f(a[1]) >= 0) a[1]--;      // 左端點向左直到 f<0
        else if (f(a[4]) <= 0) a[4]++; // 右端點向右直到 f>0
        else break;
    }

    // 三個區間求根
    for (i=1; i<4; i++)
        outfile << "根在 (" << a[i] << "," << a[i+1] << ") = "
                << bisection(a[i], a[i+1], tol) << endl;
}

測試結果驗證

// 輸入
tol = 1e-7
file = output.txt

// 輸出
函數f(x)在區間(-2.79129,-0.791288)上的根為-2
函數f(x)在區間(-0.791288,3.79129)上的根為1
函數f(x)在區間(3.79129,4.79129)上的根為4

精確根為 -2, 1, 4,驗證:(x+2)(x-1)(x-4) = x³ - 3x² - 6x + 8 ✓

工程化改進點

1. 區間擴展邏輯缺陷

原代碼 if(f(a[1])>=0) a[1]--; else if(f(a[4])<=0) a[4]++; 存在邏輯缺陷:else if 導致單邊擴展。應獨立檢查:


while (f(a[1]) >= 0) a[1] -= step;
while (f(a[4]) <= 0) a[4] += step;
// step 可自適應:初始 1.0,失敗時倍增

2. 多項式求值優化:霍納法則


#define f(x) ((1*(x) - 3)*(x) - 6)*(x) + 8  // 3 次乘法 + 3 次加法
// 避免 pow() 開銷,提升數值穩定性

3. 收斂判斷改進


while (b - a > 2*tol) {  // 等價但更清晰
    p = (a + b) * 0.5;
    if (f(p) == 0) break;  // 精確命中
    if (f(a) * f(p) < 0) b = p; else a = p;
}

4. 通用化封裝


class PolynomialRootFinder {
    std::function f_;
    double tol_;
public:
    std::vector findRealRoots(double left, double right);
    // 結合斯圖姆序列隔離根區間,再二分求根
};

數值分析視角:為什麼二分法是工程首選?

方法收斂階需導數保證收斂適用性
二分法線性 (1/2)否是 (異號區間)最廣
牛頓法二次是否 (需良好初值)光滑函數
割線法超線性 (1.618)否否無導數場景
卡丹公式解析否是僅三次

總結

三次方程二分法求根展示了數學洞察(極值點隔離根)與工程實踐(二分法保證收斂)的完美結合。雖然卡丹公式給出解析解,但二分法的無需導數、保證收斂、易於並行化、擴展到任意連續函數的特性,使其成為工程軟件中求解非線性方程的基石。掌握根區間隔離、收斂判斷、數值穩定求值,是每個計算科學工程師的必備內功。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved