昆仑山:眼中无形心中有穴之穴人合一

夫君子之行,静以修身,俭以养德;非澹泊无以明志,非宁静无以致远。夫学须静也,才须学也;非学无以广才,非志无以成学。怠慢则不能励精,险躁则不能冶性。年与时驰,意与岁去,遂成枯落,多不接世。悲守穷庐,将复何及!

 

解线性方程组迭代法+p190+1+8+C语言版

/*
 * Solving a system of linear equations using iterative methods:
 *   1. Jacobi Iterative Method (雅可比迭代法)
 *   2. Gauss-Seidel Iterative Method (高斯 - 赛德尔迭代法)
 *   3. SOR (Successive Over-Relaxation) Method (逐次超松弛迭代法)
 *
 * Target System (系数矩阵 A 需满足对角占优以保证收敛):
 *   5x1 +  2x2 + x3 =  -12
 *   -x1 +  4x2 +  2x3  =  20
 *   2x1 -  3x2 + 10x3 = 3
 *
 * Theoretical Exact Solution: x1 = -4, x2 = 3, x3 = 2
 */

#include <stdio.h>
#include <math.h>

#define N       3           /* 未知数个数 (number of unknowns) */
#define MAX_IT  1000        /* 最大迭代次数,防止不收敛时死循环 */
#define TOL     1e-8        /* 收敛容差 (convergence tolerance),使用无穷范数判断 */

/* ------------------------------------------------------------------ */
/*  Print a solution vector
 *  功能:格式化打印解向量 x 的各个分量
 * ------------------------------------------------------------------ */
static void print_solution(const double x[N])
{
    for (int i = 0; i < N; i++)
        // 输出格式:x1 = value, 保留 8 位小数
        printf("  x%d = %12.8f\n", i + 1, x[i]);
}

/* ------------------------------------------------------------------ */
/*  Infinity-norm of the difference between two vectors
 *  功能:计算两个向量差的无穷范数 (max|a_i - b_i|)
 *  用途:作为迭代收敛的判断依据。当误差小于 TOL 时,认为已收敛。
 * ------------------------------------------------------------------ */
static double inf_norm_diff(const double a[N], const double b[N])
{
    double max = 0.0;
    for (int i = 0; i < N; i++) {
        double d = fabs(a[i] - b[i]); // 计算当前分量的绝对误差
        if (d > max) max = d;         // 更新最大误差
    }
    return max;
}

/* ================================================================== */
/*  1. JACOBI METHOD (雅可比迭代法)
 *  核心思想:在第 k+1 次迭代计算 x_i 时,全部使用第 k 次迭代的旧值。
 *  公式:x_i^(k+1) = (b_i - Σ_{j!=i} A_ij * x_j^(k)) / A_ii
 *  特点:易于并行化,但收敛速度通常慢于 Gauss-Seidel。
 * ================================================================== */
void jacobi(void)
{
    printf("============================================================\n");
    printf(" Jacobi Iterative Method\n");
    printf("============================================================\n");

    /* 系数矩阵 A (Coefficient Matrix) 和 右端向量 b (RHS Vector) */
    double A[N][N] = {
            { 5, 2,  1},
            {-1,  4, 2},
            { 2, -3,  10}
    };
    double b[N] = {-12, 20, 3};

    double x[N]    = {0, 0, 0};   /* 当前迭代值 (current iterate), 初始化为 0 */
    double x_new[N];              /* 下一次迭代值 (next iterate), 暂存新结果 */
    int    iter    = 0;           /* 迭代计数器 */
    double err;                   /* 当前误差 */

    // 打印表头
    printf(" k  |   x1            x2            x3          | error\n");
    printf("----+------------------------------------------------+----------\n");

    do {
        /* Jacobi 更新核心循环:
         * 注意:计算 x_new[i] 时,右侧全部使用 x[j] (旧值),
         * 即使 j < i 已经计算出新的 x_new[j],在本轮也不使用。
         */
        for (int i = 0; i < N; i++) {
            double sigma = 0.0;
            // 计算非对角线元素的加权和:Σ_{j!=i} A_ij * x_j
            for (int j = 0; j < N; j++)
                if (j != i) sigma += A[i][j] * x[j];

            // 应用迭代公式
            x_new[i] = (b[i] - sigma) / A[i][i];
        }

        // 计算新旧向量之间的无穷范数误差
        err = inf_norm_diff(x_new, x);
        iter++;

        // 将新值覆盖旧值,准备下一轮迭代
        for (int i = 0; i < N; i++) x[i] = x_new[i];

        // 控制输出频率:前 10 次每次打印,之后每 10 次打印一次
        if (iter <= 10 || iter % 10 == 0)
            printf(" %-3d | %12.8f  %12.8f  %12.8f | %.2e\n",
                   iter, x[0], x[1], x[2], err);

    } while (err > TOL && iter < MAX_IT); // 收敛条件:误差<TOL 或 达到最大迭代次数

    printf("\n Converged after %d iterations\n", iter);
    printf(" Solution:\n");
    print_solution(x);
    printf("\n");
}

/* ================================================================== */
/*  2. GAUSS-SEIDEL METHOD (高斯 - 赛德尔迭代法)
 *  核心思想:在第 k+1 次迭代计算 x_i 时,对于 j < i 的分量,立即使用
 *  刚刚更新过的 x_j^(k+1) 新值;对于 j > i 的分量,仍使用旧值 x_j^(k)。
 *  公式:x_i^(k+1) = (b_i - Σ_{j<i} A_ij*x_j^(k+1) - Σ_{j>i} A_ij*x_j^(k)) / A_ii
 *  特点:通常比 Jacobi 收敛更快,因为利用了最新信息。
 * ================================================================== */
void gauss_seidel(void)
{
    printf("============================================================\n");
    printf(" Gauss-Seidel Iterative Method\n");
    printf("============================================================\n");

    double A[N][N] = {
            { 5, 2,  1},
            {-1,  4, 2},
            { 2, -3,  10}
    };
    double b[N] = {-12, 20, 3};

    double x[N]     = {0, 0, 0};
    double x_old[N]; // 用于保存上一轮迭代结果,以便计算误差
    int    iter     = 0;
    double err;

    printf(" k  |   x1            x2            x3          | error\n");
    printf("----+------------------------------------------------+----------\n");

    do {
        // 保存旧值用于误差计算 (因为 x 数组会在循环中被就地更新)
        for (int i = 0; i < N; i++) x_old[i] = x[i];

        /* Gauss-Seidel 更新核心循环:
         * 注意:计算 x[i] 时,如果 j < i,使用的 x[j] 已经是本轮更新过的新值。
         * 这体现了"即时更新"的特性。
         */
        for (int i = 0; i < N; i++) {
            double sigma = 0.0;
            for (int j = 0; j < N; j++)
                if (j != i) sigma += A[i][j] * x[j]; // x[j] 可能是新值也可能是旧值

            x[i] = (b[i] - sigma) / A[i][i]; // 就地更新
        }

        // 计算当前解与上一轮解的误差
        err = inf_norm_diff(x, x_old);
        iter++;

        if (iter <= 10 || iter % 10 == 0)
            printf(" %-3d | %12.8f  %12.8f  %12.8f | %.2e\n",
                   iter, x[0], x[1], x[2], err);

    } while (err > TOL && iter < MAX_IT);

    printf("\n Converged after %d iterations\n", iter);
    printf(" Solution:\n");
    print_solution(x);
    printf("\n");
}

/* ================================================================== */
/*  3. SOR METHOD (逐次超松弛迭代法)
 *  核心思想:在 Gauss-Seidel 的基础上引入松弛因子 omega (ω)。
 *  公式:x_i^(k+1) = (1-ω)*x_i^(k) + ω * (GS_step)
 *  其中 GS_step 是高斯 - 赛德尔的一步计算结果。
 *  - 若 ω = 1.0,退化为 Gauss-Seidel 方法。
 *  - 若 1.0 < ω < 2.0,称为超松弛,旨在加速收敛。
 *  - 若 0.0 < ω < 1.0,称为低松弛,有时用于改善稳定性。
 * ================================================================== */
void sor(double omega)
{
    printf("============================================================\n");
    printf(" SOR Method  (omega = %.2f)\n", omega);
    printf("============================================================\n");

    double A[N][N] = {
            { 5, 2,  1},
            {-1,  4, 2},
            { 2, -3,  10}
    };
    double b[N] = {-12, 20, 3};

    double x[N]     = {0, 0, 0};
    double x_old[N];
    int    iter     = 0;
    double err;

    printf(" k  |   x1            x2            x3          | error\n");
    printf("----+------------------------------------------------+----------\n");

    do {
        for (int i = 0; i < N; i++) x_old[i] = x[i];

        for (int i = 0; i < N; i++) {
            double sigma = 0.0;
            for (int j = 0; j < N; j++)
                if (j != i) sigma += A[i][j] * x[j];

            /* 第一步:计算标准的 Gauss-Seidel 预测值 */
            double gs = (b[i] - sigma) / A[i][i];

            /* 第二步:应用松弛因子进行加权平均 */
            // x_new = (1-ω)*x_old + ω*gs
            x[i] = (1.0 - omega) * x[i] + omega * gs;
        }

        err = inf_norm_diff(x, x_old);
        iter++;

        if (iter <= 10 || iter % 10 == 0)
            printf(" %-3d | %12.8f  %12.8f  %12.8f | %.2e\n",
                   iter, x[0], x[1], x[2], err);

    } while (err > TOL && iter < MAX_IT);

    printf("\n Converged after %d iterations\n", iter);
    printf(" Solution:\n");
    print_solution(x);
    printf("\n");
}

/* ================================================================== */
/*  MAIN FUNCTION
 *  程序入口:初始化参数并依次调用三种算法进行求解
 * ================================================================== */
int main(void)
{
    printf("\n");
    printf("  System of linear equations:\n");

    // 【已修复】此处打印的方程组系数现在与代码中定义的矩阵 A 完全一致
    printf("    5x1 +  2x2 + 1x3 =  -12\n");
    printf("   -x1 +  4x2 +  2x3  =  20\n");
    printf("   2x1 -  3x2 + 10x3 = 3\n");

    // 此处打印的精确解现在与代码中矩阵 A 和 b 的真实解一致
    printf("  Exact solution: x1=-4, x2=3, x3=2\n");
    printf("  Tolerance: %.0e,  Max iterations: %d\n\n", TOL, MAX_IT);

    // 执行 Jacobi 迭代
    jacobi();

    // 执行 Gauss-Seidel 迭代
    gauss_seidel();

    // 执行 SOR 迭代,测试不同的松弛因子
    // 循环条件改为动态计算数组长度,确保测试所有 4 个 omega 值
    double omegas[] = {0.9, 1.03, 1.0, 1.1};
    int num_omegas = sizeof(omegas) / sizeof(omegas[0]);

    for (int k = 0; k < num_omegas; k++)
        sor(omegas[k]);

    return 0;
}




posted on 2026-03-13 10:54  Indian_Mysore  阅读(0)  评论(0)    收藏  举报

导航