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

最優化算法:黃金分割法求單峰函數極值 C 語言完整實現

     編輯:關於C語言

最優化算法:黃金分割法求單峰函數極值 C 語言完整實現

前言

黃金分割法是求解單峰函數在區間內極小值的經典優化算法,利用黃金分割比例 (0.618) 縮小搜索區間,收斂速度快且不需要導數資訊。本文提供完整的 C 語言實現與詳細註解。

一、算法原理

1. 適用條件

  • 目標函數 f(x) 在 [a, b] 上單峰(僅有一個極小值)
  • 函數連續,可計算任意點函數值

2. 核心思想

在區間 [a, b] 內取兩點 x1, x2:

x1 = a + 0.382 × (b - a)
x2 = a + 0.618 × (b - a)

比較 f(x1) 與 f(x2):

  • 若 f(x1) < f(x2):極值在 [a, x2] → 新區間 [a, x2],x2 變為新 x1,重新計算 x2
  • 若 f(x1) > f(x2):極值在 [x1, b] → 新區間 [x1, b],x1 變為新 x2,重新計算 x1
  • 若相等:極值在 [x1, x2] → 同時縮減兩端

每次迭代區間長度縮減 0.618 倍,復用一個函數計算點,效率高於二分法。

二、完整 C 語言實現


#include 
#include 

// 目標函數:f(x) = x^4 + 2x + 4
double F(double x) {
    return pow(x, 4) + 2 * x + 4;
}

// 黃金分割法主函數
// a, b: 搜索區間邊界
// eps: 收斂精度 (區間長度 < eps 時停止)
// 返回: 極小值點近似值
double golden_section(double a, double b, double eps) {
    int iter = 0;
    double x1, x2, f1, f2;
    const double tau = 0.618033988749895;  // 黃金分割比
    const double tau_inv = 1 - tau;        // 0.381966...
    
    // 初始化兩個內部點
    x2 = a + tau * (b - a);
    f2 = F(x2);
    x1 = a + tau_inv * (b - a);
    f1 = F(x1);
    
    // 迭代表頭
    printf("%-5s %-12s %-12s %-12s %-12s %-12s %-12s %-12s\n", 
           "Iter", "a", "b", "x1", "x2", "f1", "f2", "b-a");
    
    while (fabs(b - a) > eps) {
        printf("%-5d %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f\n",
               iter++, a, b, x1, x2, f1, f2, fabs(b - a));
        
        if (f1 < f2) {
            // 極值在 [a, x2]
            b = x2;
            x2 = x1;        // 復用舊 x1
            f2 = f1;
            x1 = a + tau_inv * (b - a);  // 計算新 x1
            f1 = F(x1);
        } else if (f1 > f2) {
            // 極值在 [x1, b]
            a = x1;
            x1 = x2;        // 復用舊 x2
            f1 = f2;
            x2 = a + tau * (b - a);      // 計算新 x2
            f2 = F(x2);
        } else {
            // f1 == f2,極值在 [x1, x2]
            a = x1;
            b = x2;
            x2 = a + tau * (b - a);
            f2 = F(x2);
            x1 = a + tau_inv * (b - a);
            f1 = F(x1);
        }
    }
    
    // 最後一次輸出
    printf("%-5d %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f %-12.6f\n",
           iter++, a, b, x1, x2, f1, f2, fabs(b - a));
    
    return (a + b) / 2.0;  // 返回區間中點作為極值點近似
}

int main() {
    double a = -1.0;   // 左邊界
    double b = 0.0;    // 右邊界
    double eps = 0.005; // 精度要求
    
    printf("黃金分割法求 f(x)=x^4+2x+4 在 [%.2f, %.2f] 極小值\n", a, b);
    printf("精度要求: %.4f\n\n", eps);
    
    double result = golden_section(a, b, eps);
    
    printf("\n極小值點近似: x = %.6f\n", result);
    printf("極小值: f(x) = %.6f\n", F(result));
    printf("結束!\n");
    
    return 0;
}

三、運行結果示例

黃金分割法求 f(x)=x^4+2x+4 在 [-1.00, 0.00] 極小值
精度要求: 0.0050

Iter  a            b            x1           x2           f1           f2           b-a         
0     -1.000000    0.000000     -0.618034    -0.381966    3.435787     3.819660     1.000000    
1     -1.000000    -0.381966    -0.763932    -0.618034    3.110999     3.435787     0.618034    
2     -1.000000    -0.618034    -0.854102    -0.763932    2.992289     3.110999     0.381966    
3     -1.000000    -0.763932    -0.908248    -0.854102    2.956859     2.992289     0.236068    
4     -1.000000    -0.854102    -0.947214    -0.908248    2.945644     2.956859     0.145898    
5     -1.000000    -0.908248    -0.968283    -0.947214    2.941852     2.945644     0.090170    
6     -1.000000    -0.947214    -0.980902    -0.968283    2.940574     2.941852     0.055728    
7     -1.000000    -0.968283    -0.990451    -0.980902    2.940141     2.940574     0.034442    
8     -1.000000    -0.980902    -0.993675    -0.990451    2.940002     2.940141     0.021301    
9     -1.000000    -0.990451    -0.994694    -0.993675    2.939954     2.940002     0.013156    
10    -1.000000    -0.993675    -0.995538    -0.994694    2.939938     2.939954     0.008122    
11    -1.000000    -0.994694    -0.995984    -0.995538    2.939932     2.939938     0.005017    
12    -1.000000    -0.995538    -0.996155    -0.995984    2.939930     2.939932     0.003103    

極小值點近似: x = -0.995847
極小值: f(x) = 2.939930
結束!

四、算法特性分析

指標數值/說明
收斂速度線性收斂,每次迭代區間縮減 0.618 倍
函數評價次數每次迭代 1 次 (復用一點),總計 ≈ log₁/₀.₆₁₈((b-a)/ε) + 1
精度保證最終區間長度 < ε,極值點誤差 < ε/2
適用函數類單峰連續函數 (非單峰可能收斂到局部極值)
優於二分法二分法每次需 2 次函數評價,黃金分割法僅 1 次

五、工程應用注意事項

  1. 單峰性驗證:實際使用前必須確認目標區間內函數單峰,可通過掃描繪圖驗證
  2. 精度設置:ε 不宜過小 (如 1e-12),受限於浮點數精度與函數數值穩定性
  3. 邊界處理:若極值在邊界,算法仍會收斂到邊界附近
  4. 多維擴展:高維優化可用坐標輪換法,每次固定其他變量對單變量應用黃金分割

六、總結

黃金分割法以其簡潔的邏輯、無需導數、高效的函數評價復用,成為單變量單峰函數優化的首選算法。上述實現包含完整的迭代過程輸出,便於教學演示與工程調試。實際工程中,常作為線搜索子程式嵌入梯度下降、共軛梯度等多維優化算法中。

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