使用 C 语言中的牛顿法近似求解根

CCBeginner
立即练习

💡 本教程由 AI 辅助翻译自英文原版。如需查看原文,您可以 切换至英文原版

简介

在本实验中,你将学习如何使用C语言中的牛顿法来近似函数的根。本实验涵盖以下步骤:

首先,你将定义函数f(x)及其导数f'(x)。然后,你将实现牛顿法的迭代公式来计算近似根。最后,你将打印得到的近似根。

本实验提供了一个使用C编程应用数值方法解决数学问题的实际示例。在实验结束时,你将更好地理解如何使用牛顿法来找到函数的根。


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL c(("C")) -.-> c/BasicsGroup(["Basics"]) c(("C")) -.-> c/ControlFlowGroup(["Control Flow"]) c(("C")) -.-> c/FunctionsGroup(["Functions"]) c(("C")) -.-> c/UserInteractionGroup(["User Interaction"]) c/BasicsGroup -.-> c/variables("Variables") c/ControlFlowGroup -.-> c/for_loop("For Loop") c/FunctionsGroup -.-> c/math_functions("Math Functions") c/UserInteractionGroup -.-> c/output("Output") subgraph Lab Skills c/variables -.-> lab-435133{{"使用 C 语言中的牛顿法近似求解根"}} c/for_loop -.-> lab-435133{{"使用 C 语言中的牛顿法近似求解根"}} c/math_functions -.-> lab-435133{{"使用 C 语言中的牛顿法近似求解根"}} c/output -.-> lab-435133{{"使用 C 语言中的牛顿法近似求解根"}} end

定义 f(x) 和 f'(x)

在这一步中,我们将定义数学函数 f(x) 及其导数 f'(x),以便实现牛顿法来近似根。

首先,让我们在 ~/project 目录中创建一个新的C文件:

cd ~/project
nano newton_method.c

现在,让我们编写初始代码来定义我们的函数及其导数:

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

// 定义函数 f(x)
double f(double x) {
    return x * x - 4;  // 示例函数:f(x) = x^2 - 4
}

// 定义导数 f'(x)
double f_derivative(double x) {
    return 2 * x;  // f(x) 的导数 = 2x
}

int main() {
    printf("函数 f(x) = x^2 - 4\n");
    printf("导数 f'(x) = 2x\n");
    return 0;
}

示例输出:

函数 f(x) = x^2 - 4
导数 f'(x) = 2x

让我们来分析一下这段代码:

  • f(x) 被定义为 x^2 - 4,其根为 x = 2 和 x = -2
  • f_derivative(x) 是 f(x) 的导数,即 2x
  • 我们将在接下来的步骤中使用这些函数来实现牛顿法

编译代码以进行验证:

gcc -o newton_method newton_method.c -lm
./newton_method

迭代 x_{n + 1} = x_n - \frac{f(x_n)}{f'(x_n)}

在这一步中,我们将实现牛顿法的迭代公式,以近似我们函数的根。

打开之前的 newton_method.c 文件:

cd ~/project
nano newton_method.c

更新代码以包含牛顿法迭代:

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

// 之前的函数定义保持不变
double f(double x) {
    return x * x - 4;
}

double f_derivative(double x) {
    return 2 * x;
}

// 牛顿法实现
double newton_method(double initial_guess, int max_iterations, double tolerance) {
    double x = initial_guess;

    for (int i = 0; i < max_iterations; i++) {
        double fx = f(x);
        double fpx = f_derivative(x);

        // 检查除零情况
        if (fabs(fpx) < tolerance) {
            printf("导数过于接近零。无法继续。\n");
            return x;
        }

        // 牛顿法迭代公式
        double x_next = x - fx / fpx;

        printf("第 %d 次迭代: x = %f\n", i + 1, x_next);

        // 检查收敛情况
        if (fabs(x_next - x) < tolerance) {
            return x_next;
        }

        x = x_next;
    }

    printf("达到最大迭代次数。\n");
    return x;
}

int main() {
    double initial_guess = 1.0;
    int max_iterations = 10;
    double tolerance = 1e-6;

    double root = newton_method(initial_guess, max_iterations, tolerance);

    printf("\n近似根: %f\n", root);
    printf("f(根) = %f\n", f(root));

    return 0;
}

编译并运行代码:

gcc -o newton_method newton_method.c -lm
./newton_method

示例输出:

第 1 次迭代: x = 2.500000
第 2 次迭代: x = 2.050000
第 3 次迭代: x = 2.000610
第 4 次迭代: x = 2.000000
第 5 次迭代: x = 2.000000

近似根: 2.000000
f(根) = 0.000000

实现的关键点:

  • newton_method() 接受初始猜测值、最大迭代次数和容差
  • 实现牛顿法迭代公式:x_{n + 1} = x_n - \frac{f(x_n)}{f'(x_n)}
  • 检查收敛情况和潜在的除零情况
  • 打印中间迭代结果以展示近似过程

打印近似根

在这一步中,我们将改进牛顿法的实现,以提供关于根近似的更详细输出。

打开之前的 newton_method.c 文件:

cd ~/project
nano newton_method.c

更新代码以改进根近似输出:

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

// 之前的函数和方法定义保持不变
double f(double x) {
    return x * x - 4;
}

double f_derivative(double x) {
    return 2 * x;
}

double newton_method(double initial_guess, int max_iterations, double tolerance) {
    double x = initial_guess;

    printf("牛顿法根近似\n");
    printf("-----------------------------------\n");
    printf("初始猜测值: %f\n", x);
    printf("容差: %e\n", tolerance);
    printf("最大迭代次数: %d\n\n", max_iterations);

    for (int i = 0; i < max_iterations; i++) {
        double fx = f(x);
        double fpx = f_derivative(x);

        if (fabs(fpx) < tolerance) {
            printf("错误: 导数过于接近零。\n");
            return x;
        }

        double x_next = x - fx / fpx;

        printf("第 %d 次迭代:\n", i + 1);
        printf("  当前 x: %f\n", x_next);
        printf("  f(x): %f\n", f(x_next));
        printf("  |x_next - x|: %e\n\n", fabs(x_next - x));

        if (fabs(x_next - x) < tolerance) {
            printf("已收敛!\n");
            return x_next;
        }

        x = x_next;
    }

    printf("达到最大迭代次数。\n");
    return x;
}

int main() {
    double initial_guess = 1.0;
    int max_iterations = 10;
    double tolerance = 1e-6;

    double root = newton_method(initial_guess, max_iterations, tolerance);

    printf("最终结果:\n");
    printf("-------------\n");
    printf("近似根: %f\n", root);
    printf("f(根): %f\n", f(root));
    printf("绝对误差: %e\n", fabs(f(root)));

    return 0;
}

编译并运行代码:

gcc -o newton_method newton_method.c -lm
./newton_method

示例输出:

牛顿法根近似
-----------------------------------
初始猜测值: 1.000000
容差: 1.000000e-06
最大迭代次数: 10

第 1 次迭代:
  当前 x: 2.500000
  f(x): 2.250000
  |x_next - x|: 1.500000e+00

第 2 次迭代:
  当前 x: 2.050000
  f(x): 0.202500
  |x_next - x|: 4.500000e-01

...(更多迭代)

已收敛!

最终结果:
-------------
近似根: 2.000000
f(根): 0.000000
绝对误差: 0.000000e+00

主要改进:

  • 添加了详细的迭代信息
  • 显示了初始参数
  • 展示了收敛进度
  • 打印了带有绝对误差的最终结果

总结

在本实验中,我们首先定义了数学函数 f(x) 及其导数 f'(x),以实现用于近似根的牛顿法。然后,我们实现了迭代公式 x_{n + 1} = x_n - \frac{f(x_n)}{f'(x_n)} 来进行根的近似。最后,我们将打印通过此过程获得的近似根。

本实验涵盖的关键步骤是定义目标函数及其导数,然后迭代应用牛顿法公式以收敛到根。这种方法使我们能够使用C编程有效地找到各种数学函数的根。