2、数值积分基础:黎曼和与积分定义、左端点、右端点、中点法则

2.1 从物理问题说起

我记得刚入行做仿真那会儿,遇到一个很头疼的问题。一个运动物体的速度曲线是已知的,但位移怎么算?

你想想看,如果速度是恒定的,那很简单——速度乘以时间就行。但现实世界哪有这么理想?速度总是在变。这时候,数值积分就派上用场了。

说白了,数值积分就是「用近似的方法求曲线下的面积」。我们没法像数学公式那样精确,但我们可以做到足够好。

2.2 黎曼和:最朴素的积分思想

黎曼和的思想其实特别朴素。你想求一个函数 f(x) 在区间 [a, b] 上的积分,怎么办?

把区间切成 n 个小段,每段取一个代表点,用这个点的函数值乘以段宽度,然后加起来。这就是黎曼和。

核心公式:
∫[a,b] f(x) dx ≈ Σ[i=1 to n] f(xi*) * Δx

其中 Δx = (b-a)/n,xi* 是第 i 个子区间内的某个点。

我在项目中遇到过不少新手,一上来就追求高精度算法,结果代码写得很复杂,调试半天还跑不通。其实很多时候,黎曼和就能解决问题。别小看它。

2.3 左端点法则

左端点法则,就是取每个子区间的左端点作为代表点。

左端点法则公式:
∫[a,b] f(x) dx ≈ Δx * [f(x0) + f(x1) + ... + f(xn-1)]

其中 xi = a + i * Δx, i = 0, 1, ..., n-1

嗯,这里要注意。左端点法则有个特点——它总是低估单调递增函数的积分,高估单调递减函数的积分。为什么?因为左端点的函数值小于(或大于)区间内的平均值。

我的经验: 如果函数变化比较平缓,左端点法则其实够用。我在做传感器数据仿真时,经常用这个法则,因为数据采集本身就是离散的,左端点法则最符合物理意义。

2.4 右端点法则

右端点法则跟左端点法则对称,取每个子区间的右端点。

右端点法则公式:
∫[a,b] f(x) dx ≈ Δx * [f(x1) + f(x2) + ... + f(xn)]

其中 xi = a + i * Δx, i = 1, 2, ..., n

右端点法则的误差特性跟左端点法则正好相反。它高估单调递增函数的积分,低估单调递减函数的积分。

我曾经犯过一个错误——用右端点法则计算一个快速衰减的指数函数积分,结果误差大得离谱。后来才意识到,对于这种函数,应该用左端点法则或者中点法则。

2.4 中点法则:更聪明的选择

中点法则取每个子区间的中点作为代表点。你想想看,中点往往比端点更能代表整个区间的平均水平。

中点法则公式:
∫[a,b] f(x) dx ≈ Δx * [f(x0.5) + f(x1.5) + ... + f(xn-0.5)]

其中 xi+0.5 = a + (i + 0.5) * Δx, i = 0, 1, ..., n-1
关键点: 中点法则的误差比左端点和右端点法则小一个数量级。左/右端点法则的误差是 O(Δx),中点法则的误差是 O(Δx²)。

为什么会这样?因为中点法则的误差项中,一阶项相互抵消了。说白了,就是中点能更好地捕捉函数在区间内的平均行为。

2.5 三种法则的对比

法则 代表点位置 误差阶数 适用场景
左端点法则 左端点 O(Δx) 单调递减函数、数据采集仿真
右端点法则 右端点 O(Δx) 单调递增函数、实时系统
中点法则 中点 O(Δx²) 一般情况、精度要求较高
避坑指南: 我曾经在仿真一个振荡信号时,用了左端点法则,结果积分结果完全偏离物理规律。因为振荡信号的正负部分相互抵消,左端点法则无法准确捕捉这种抵消效应。后来换成中点法则,问题就解决了。

2.6 知识体系图

下面这张图展示了本章的核心逻辑——从连续积分到离散近似的完整路径。

数值积分基础:黎曼和与三种法则 连续积分 ∫f(x)dx 黎曼和:离散近似 左端点法则 中点法则 右端点法则 误差 O(Δx) 误差 O(Δx²) ★ 误差 O(Δx) 核心思想:用离散点的函数值近似连续曲线下的面积

2.7 代码示例:三种法则的实现

下面是一个简单的 Python 实现,对比三种法则的效果。

import numpy as np

def left_riemann(f, a, b, n):
    """左端点法则"""
    dx = (b - a) / n
    x = np.linspace(a, b - dx, n)  # 左端点
    return np.sum(f(x)) * dx

def right_riemann(f, a, b, n):
    """右端点法则"""
    dx = (b - a) / n
    x = np.linspace(a + dx, b, n)  # 右端点
    return np.sum(f(x)) * dx

def midpoint_riemann(f, a, b, n):
    """中点法则"""
    dx = (b - a) / n
    x = np.linspace(a + dx/2, b - dx/2, n)  # 中点
    return np.sum(f(x)) * dx

# 测试函数:f(x) = x²
def f(x):
    return x**2

a, b = 0, 1
exact = 1/3  # 精确值

for n in [10, 100, 1000]:
    L = left_riemann(f, a, b, n)
    R = right_riemann(f, a, b, n)
    M = midpoint_riemann(f, a, b, n)
    print(f"n={n}: 左={L:.6f}, 右={R:.6f}, 中={M:.6f}, 精确={exact:.6f}")
我的建议: 实际项目中,如果对精度要求不高(比如误差在1%以内),用中点法则配合 n=100 左右就足够了。别一上来就搞什么自适应积分,先把基础打牢。

嗯,这一章的内容就到这里。黎曼和是数值积分的基石,左端点、右端点、中点法则是最基本的三种实现方式。理解它们的误差特性,比死记公式重要得多。


专注资料整理