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