问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

定积分的三种数值解法:梯形法、矩形法和辛普森法

创作时间:
作者:
@小白创作中心

定积分的三种数值解法:梯形法、矩形法和辛普森法

引用
CSDN
1.
https://blog.csdn.net/2401_87089860/article/details/145304590

定积分的数值解法是通过近似方法计算积分值,适用于无法直接求解或解析解复杂的情况。以下是三种常见的数值积分方法:梯形法、矩形法和辛普森法。它们的基本思想是将积分区间划分为若干小区间,并用简单的几何形状(如矩形、梯形或抛物线)近似函数曲线下的面积。

梯形法

基本思想:
将积分区间$[a, b]$分成$n$个小区间,每个小区间的长度为$\Delta x = \frac{b - a}{n}$。把每个小区间上的曲边梯形近似看成梯形,通过计算这些梯形面积的和来近似定积分的值。

计算公式:
$$
\int_{a}^{b}f(x)dx \approx \frac{\Delta x}{2}\left[f(x_0) + 2f(x_1) + 2f(x_2) + \cdots + 2f(x_{n - 1}) + f(x_n)\right]
$$
其中$x_i = a + i\Delta x$,$i = 0,1,\cdots,n$。

矩形法

基本思想:
同样将积分区间$[a, b]$分成$n$个小区间,每个小区间长度为$\Delta x = \frac{b - a}{n}$。不过这里是用每个小区间上的矩形面积来近似小曲边梯形的面积,进而得到定积分的近似值。矩形的高度可以取小区间的左端点函数值、右端点函数值或中点函数值。

计算公式:

  • 左矩形公式:
    $$
    \int_{a}^{b}f(x)dx \approx \Delta x\left[f(x_0) + f(x_1) + f(x_2) + \cdots + f(x_{n - 1})\right]
    $$
    其中$x_i = a + i\Delta x$,$i = 0,1,\cdots,n - 1$。

  • 右矩形公式:
    $$
    \int_{a}^{b}f(x)dx \approx \Delta x\left[f(x_1) + f(x_2) + f(x_3) + \cdots + f(x_n)\right]
    $$
    其中$x_i = a + i\Delta x$,$i = 1,2,\cdots,n$。

  • 中矩形公式:
    $$
    \int_{a}^{b}f(x)dx \approx \Delta x\left[f\left(\frac{x_0 + x_1}{2}\right) + f\left(\frac{x_1 + x_2}{2}\right) + \cdots + f\left(\frac{x_{n - 1} + x_n}{2}\right)\right]
    $$
    其中$x_i = a + i\Delta x$,$i = 0,1,\cdots,n - 1$。

辛普森法

基本思想:
把积分区间$[a, b]$分成$n$个小区间($n$为偶数),每个小区间长度为$\Delta x = \frac{b - a}{n}$。在每个小区间上,用二次函数来近似代替被积函数,通过计算这些二次函数在小区间上的定积分来近似原函数的定积分。

计算公式:
$$
\int_{a}^{b}f(x)dx \approx \frac{\Delta x}{3}\left[f(x_0) + 4f(x_1) + 2f(x_2) + 4f(x_3) + \cdots + 2f(x_{n - 2}) + 4f(x_{n - 1}) + f(x_n)\right]
$$
其中$x_i = a + i\Delta x$,$i = 0,1,\cdots,n$。

这三种方法各有优缺点。梯形法计算相对简单,但精度一般;矩形法计算简便,适用于一些简单的近似计算,但误差相对较大;辛普森法精度较高,但计算量相对较大,且要求区间划分是偶数个。在实际应用中,可根据具体问题的要求和被积函数的特点选择合适的方法。

C++代码实现

#include <iostream>
#include <cmath>
#define pi 3.1415926535  // 定义圆周率π的值
using namespace std;

// 基类,定义积分函数和积分区间
class fx {
protected:
    double a, b;  // 积分下限和上限
    static double y;  // 用于存储函数值的静态变量
public:
    // 构造函数,初始化积分区间
    fx(double A = 0, double B = 0) {
        a = A;
        b = B;
    }
    // 设置积分区间的函数
    void setfxa_b(double A = 0, double B = 0) {
        a = A;
        b = B;
    }
    // 定义被积函数 f(x) = sin(x)
    double f(double x) {
        y = sin(x);  // 计算 sin(x) 的值并存储到 y 中
        return y;    // 返回函数值
    }
};

// 初始化静态变量 y
double fx::y = 0;

// 矩形法类,继承自基类 fx
class rectencle : public fx {
public:
    double step, ans;  // 定义步长和积分结果
    int p;             // 定义区间划分的份数
    // 构造函数,初始化积分区间、份数,并调用积分函数
    rectencle(double a, double b, int P) : fx(a, b) {
        ans = 0;       // 初始化积分结果为 0
        p = P;         // 设置区间划分份数
        getstep();     // 计算步长
        integrate();   // 调用积分函数计算结果
    }
    // 计算步长
    void getstep() {
        step = (b - a) / p * 1.0;  // 计算每个小区间的宽度
    }
    // 实现矩形法积分
    void integrate() {
        for (int i = 1; i <= p; i++) {
            ans += f(a + step * i) * step;  // 在每个小区间上取右端点的函数值计算矩形面积
        }
    }
    // 输出积分结果
    void showans() {
        cout << ans << endl;  // 输出积分结果
    }
};

// 梯形法类,继承自基类 fx
class ladder : public fx {
public:
    double step, ans;  // 定义步长和积分结果
    int p;             // 定义区间划分的份数
    // 构造函数,初始化积分区间、份数,并调用积分函数
    ladder(double a, double b, int P) : fx(a, b) {
        ans = 0;       // 初始化积分结果为 0
        p = P;         // 设置区间划分份数
        getstep();     // 计算步长
        integrate();   // 调用积分函数计算结果
    }
    // 计算步长
    void getstep() {
        step = (b - a) / p * 1.0;  // 计算每个小区间的宽度
    }
    // 实现梯形法积分
    void integrate() {
        for (int i = 1; i <= p; i++) {
            ans += (f(a + step * i) + f(a + step * (i - 1))) * step * 0.5;  // 使用梯形公式计算每个小区间的面积
        }
    }
    // 输出积分结果
    void showans() {
        cout << ans << endl;  // 输出积分结果
    }
};

// 辛普森法类,继承自基类 fx
class simpson : public fx {
public:
    double step, ans;  // 定义步长和积分结果
    int p;             // 定义区间划分的份数
    // 构造函数,初始化积分区间、份数,并调用积分函数
    simpson(double a, double b, int P) : fx(a, b) {
        ans = 0;       // 初始化积分结果为 0
        p = P;         // 设置区间划分份数
        getstep();     // 计算步长
        integrate();   // 调用积分函数计算结果
    }
    // 计算步长
    void getstep() {
        step = (b - a) / p * 1.0;  // 计算每个小区间的宽度
    }
    // 实现辛普森法积分
    void integrate() {
        double h = (b - a) / p;  // 计算步长
        ans = f(a) + f(b);       // 初始化结果为区间两端点的函数值之和
        // 遍历每个小区间,计算中间点的函数值并加权
        for (int i = 1; i <= p - 1; ++i) {
            double x = a + h * i;  // 计算当前点的 x 值
            ans += f(x) * ((i & 1) ? 4 : 2);  // 奇数点乘以 4,偶数点乘以 2
        }
        ans *= h / 3;  // 最后乘以步长的三分之一
    }
    // 输出积分结果
    void showans() {
        cout << ans << endl;  // 输出积分结果
    }
};

// 主函数,测试三种积分方法
int main() {
    rectencle test1(0, pi / 2, 10000);  // 创建矩形法对象,积分区间为 [0, π/2],划分为 10000 份
    ladder test2(0, pi / 2, 10000);     // 创建梯形法对象,积分区间为 [0, π/2],划分为 10000 份
    simpson test3(0, pi / 2, 10000);    // 创建辛普森法对象,积分区间为 [0, π/2],划分为 10000 份
    test1.showans();  // 输出矩形法的积分结果
    test2.showans();  // 输出梯形法的积分结果
    test3.showans();  // 输出辛普森法的积分结果
}

运行结果

显示精度的差异

将主函数改为:

int main() {
    int i = 1;
    cout << "rectencle:" << endl; // 测试矩形法(rectencle)
    for (; i < 1000000; i *= 10) {
        rectencle test1(0, pi / 2, i);
        test1.showans();
    }
    cout << "ladder:" << endl; // 测试梯形法(ladder)
    for (i = 1; i < 1000000; i *= 10) {
        ladder test2(0, pi / 2, i);
        test2.showans();
    }
    cout << "simpson:" << endl; // 测试辛普森法(simpson)
    for (i = 1; i < 1000000; i *= 10) {
        simpson test3(0, pi / 2, 10000);
        test3.showans();
    }
    return 0;
}

运行结果

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号