5.2 数列、级数与无穷过程
上一节建立了极限的语言,并给出了判断收敛的六条等价定理。这一节用它们处理无穷求和:把无穷多个数加起来,和会不会稳定到某个有限值。级数是分析里出现频率最高的对象之一,Taylor 展开是幂级数的和,函数的逼近是函数项级数的部分和,算法复杂度的估计靠的是级数的主项,数值计算中的求和误差则直接取决于级数的收敛速度。
级数的判敛是本节的主线。判断方法有一整套:正项级数用比较、比值、根值、积分判别,一般项级数用 Leibniz、Abel、Dirichlet 判别。这些判别法各有适用范围,其中比值与根值判别在
最后一段内容面向计算:级数的收敛速度决定数值求和的代价,交错级数可以用加速方法把误差压低几个数量级;浮点求和的累积误差与求和顺序、数据类型有关,累加
5.2.1 数列极限的补充工具
上下极限与子列
有界数列不一定收敛(如
第一个式子中的
Stolz 定理
数列版本的洛必达法则。设
则
例:求
取
由
渐近记号
比较两个数列(或函数)在极限过程中的增长快慢,用四组记号。
使用这组记号时要记住三点。第一,等号方向是单向的:
例:
递推数列
由递推关系定义的数列用单调有界定理处理最方便。步骤是三步:证明有界(常用归纳法)、证明单调、对递推式两端取极限解出极限值。
例:
5.2.2 级数的收敛与基本判据
部分和与收敛
给定数列
这个定义把级数问题完全化为数列问题,因此上一节的所有工具都可以使用。由 Cauchy 收敛准则立刻得到级数版的判据:级数收敛的充要条件是对任意
必要条件不是充分条件。调和级数
分组证明:把项按
第
积分比较:由
几何级数
5.2.3 正项级数的判别法
正项级数(
比较判别法:若
极限比较判别法:若
比值判别法:若
根值判别法:若
积分判别法:若
Cauchy 凝聚判别法:
比值与根值判别的局限
这两种判别法依赖通项本身按几何速率衰减,对幂次或对数衰减的级数无效。
5.2.4 一般项级数与条件收敛
交错级数与 Leibniz 判别
Leibniz 判别:若
即用前
Abel 与 Dirichlet 判别
两者处理「通项不是单调递减」的交错型级数。
Dirichlet 判别:若部分和
Abel 判别:若
这两条判别法的证明思路相同(分部求和,即 Abel 变换),可以理解为离散版的「分部积分」。
绝对收敛与条件收敛
若
条件收敛的级数失去所有这些性质,其中最强的一条结论是 Riemann 重排定理:条件收敛的级数经过重排可以收敛到任意给定的实数,也可以发散到
重排定理的数值形态
本节实验四把交错调和级数重排到
5.2.5 收敛速度与数值求和
误差估计
三种常用级数的截断误差有现成的估计。
几何级数:
交错级数(Leibniz 型):误差不超过下一项的绝对值
收敛加速
部分和的收敛速度可以用序列变换改善。Aitken
它的原理适用于误差按几何规律衰减的情形:若
Euler 变换处理交错级数:把它改写成对相邻项之差的级数,新级数的项衰减更快。Shanks 变换是 Aitken 方法的多项推广,Wynn 的 ε 算法用递推实现它。这些方法在特殊函数求值、常数计算与数值积分中有标准实现。
浮点求和的误差
浮点加法的每一次运算都可能引入舍入误差,误差量级是当前结果的
升序与降序的差别:把绝对值小的项放在前面累加更准。本节实验三的数据:调和级数的
补偿求和:Kahan 求和法维护一个补偿量记录每次加法的舍入损失,在下一次加法中补回。实验三中它给出的结果与精确值完全一致(误差为零)。
成对求和:NumPy 的 np.sum 使用成对(分块)求和的策略,误差约为
灾难性抵消:两个接近的大数相减会失去有效数字。实验三中的例子
5.2.6 数值实验
实验一:判别法的边界
正项级数的四个例子,观察比值与根值判别在幂次级数上的失效。
import math
print("p 级数 sum 1/n^p 的比值与根值在 n = 10^6 处:")
for p in [1.0, 1.5, 2.0]:
ratio = (10**6 / (10**6 + 1)) ** p
root = (1.0 / 10**6) ** (p / 10**6)
print(f" p = {p}: a_{{n+1}}/a_n = {ratio:.10f}, (a_n)^(1/n) = {root:.10f}")
def psum(p, n):
s = 0.0
for k in range(1, n + 1):
s += 1.0 / (k ** p)
return s
print("部分和(n = 10^6):")
print(f" sum 1/n = {psum(1.0, 10**6):.6f}(发散,仍在增长)")
print(f" sum 1/n^1.5 = {psum(1.5, 10**6):.6f}(收敛到 zeta(1.5) = 2.612375)")
print(f" sum 1/n^2 = {psum(2.0, 10**6):.10f}(收敛到 pi^2/6 = 1.6449340668)")
s = 0.0
term = 1.0
for k in range(1, 60):
term *= 2.0 / k
s += term
print(f"sum 2^n/n! (n >= 1) = {s:.10f}(收敛到 e^2 - 1 = {math.exp(2) - 1:.10f})")输出:
p 级数 sum 1/n^p 的比值与根值在 n = 10^6 处:
p = 1.0: a_{n+1}/a_n = 0.9999990000, (a_n)^(1/n) = 0.9999861846
p = 1.5: a_{n+1}/a_n = 0.9999985000, (a_n)^(1/n) = 0.9999792769
p = 2.0: a_{n+1}/a_n = 0.9999980000, (a_n)^(1/n) = 0.9999723694
部分和(n = 10^6):
sum 1/n = 14.392727(发散,仍在增长)
sum 1/n^1.5 = 2.610375(收敛到 zeta(1.5) = 2.612375)
sum 1/n^2 = 1.6449330668(收敛到 pi^2/6 = 1.6449340668)
sum 2^n/n! (n >= 1) = 6.3890560989(收敛到 e^2 - 1 = 6.3890560989)三个
第四个例子说明比值判别有效的场景:
实验二:交错级数与收敛加速
用交错调和级数(和等于
import math
def alt_partials(n):
s = 0.0
hist = []
for k in range(1, n + 1):
s += (-1.0) ** (k + 1) / k
hist.append(s)
return hist
target = math.log(2)
hist = alt_partials(1000)
for n in [10, 100, 1000]:
print(f" n = {n:>4}: s_n = {hist[n-1]:.12f}, 误差 = {abs(hist[n-1] - target):.3e}, "
f"Leibniz 界 = {1.0/(n+1):.3e}")
s0, s1, s2 = hist[-3], hist[-2], hist[-1]
d1, d2 = s1 - s0, s2 - s1
aitken = s0 - d1 * d1 / (d2 - d1)
print(f" Aitken 加速(基于 n = 998, 999, 1000): {aitken:.12f}, 误差 = {abs(aitken - target):.3e}")
print(f" 加速后误差缩小 {abs(hist[-1] - target)/abs(aitken - target):.0f} 倍")输出:
n = 10: s_n = 0.645634920635, 误差 = 4.751e-02, Leibniz 界 = 9.091e-02
n = 100: s_n = 0.688172179310, 误差 = 4.975e-03, Leibniz 界 = 9.901e-03
n = 1000: s_n = 0.692647430560, 误差 = 4.998e-04, Leibniz 界 = 9.990e-04
Aitken 加速(基于 n = 998, 999, 1000): 0.693147180435, 误差 = 1.252e-10
加速后误差缩小 3992075 倍直接求和时,误差严格按
外推的收益随截断位置的推移而增大(练习题 3 给出数据):用
实验三:浮点求和
同一个和用四种方法累加,比较误差。
import math
import numpy as np
n = 10**6
vals = [1.0 / k for k in range(1, n + 1)]
exact = math.fsum(vals)
s_up = 0.0
for v in vals:
s_up += v
s_down = 0.0
for v in reversed(vals):
s_down += v
s_kahan = 0.0
c = 0.0
for v in vals:
y = v - c
t = s_kahan + y
c = (t - s_kahan) - y
s_kahan = t
s_pair = float(np.sum(np.array(vals)))
print(f"调和级数前 10^6 项(精确值 math.fsum = {exact:.10f}):")
print(f" 升序朴素求和: {s_up:.10f}, 误差 = {abs(s_up - exact):.3e}")
print(f" 降序朴素求和: {s_down:.10f}, 误差 = {abs(s_down - exact):.3e}")
print(f" Kahan 补偿求和: {s_kahan:.10f}, 误差 = {abs(s_kahan - exact):.3e}")
print(f" NumPy 成对求和: {s_pair:.10f}, 误差 = {abs(s_pair - exact):.3e}")
s_cancel = 0.0
for k in range(1, n + 1):
s_cancel += 1.0 / k - 1.0 / (k + 1)
formula = 1.0 - 1.0 / (n + 1)
print(f"sum (1/k - 1/(k+1)) 的朴素求和 = {s_cancel:.12f},"
f"telescoping 精确结果 = {formula:.12f},差 = {abs(s_cancel - formula):.3e}")输出:
调和级数前 10^6 项(精确值 math.fsum = 14.3927267229):
升序朴素求和: 14.3927267229, 误差 = 7.354e-13
降序朴素求和: 14.3927267229, 误差 = 4.796e-14
Kahan 补偿求和: 14.3927267229, 误差 = 0.000e+00
NumPy 成对求和: 14.3927267229, 误差 = 1.776e-15
sum (1/k - 1/(k+1)) 的朴素求和 = 0.999999000001,telescoping 精确结果 = 0.999999000001,差 = 4.696e-14四种方法的精度排序与理论预期一致。升序朴素求和把大项先加上去,之后的小项在与大数相加时被舍去一部分,误差
误差还随项数增长。同样的升序朴素求和,
最后一个例子是灾难性抵消:
实验四:重排改变级数的和
交错调和级数是条件收敛的典型例子,按「先用正项超过目标、再用负项压回目标以下」的规则重排,观察部分和的轨迹。
import math
target_sum = 1.5
s = 0.0
pos = 1 # 下一个正项的分母(奇数)
neg = 1 # 下一个负项的分母(偶数)
for step in range(200000):
if s <= target_sum:
s += 1.0 / pos
pos += 2
else:
s -= 1.0 / neg
neg += 2
if step in (0, 20, 100, 1000, 10000, 100000, 199999):
print(f" 前 {step + 1:>6} 项: 部分和 = {s:.6f}(已用正项 {pos // 2 + 1} 个,"
f"负项 {neg // 2} 个)")
print(f" 原顺序(交错级数)的极限 = ln 2 = {math.log(2):.6f}")输出:
前 1 项: 部分和 = 1.000000(已用正项 2 个,负项 0 个)
前 21 项: 部分和 = 1.479673(已用正项 21 个,负项 1 个)
前 101 项: 部分和 = 1.476630(已用正项 97 个,负项 5 个)
前 1001 项: 部分和 = 1.494198(已用正项 954 个,负项 48 个)
前 10001 项: 部分和 = 1.499233(已用正项 9527 个,负项 475 个)
前 100001 项: 部分和 = 1.499960(已用正项 95259 个,负项 4743 个)
前 200000 项: 部分和 = 1.499954(已用正项 190515 个,负项 9486 个)
原顺序(交错级数)的极限 = ln 2 = 0.693147重排后的部分和在
这个实验是 Riemann 重排定理的直观形态:条件收敛的级数不带任何「顺序依赖」的和,任意指定的目标值都可以通过重排达到。绝对收敛的级数没有这个性质,重排不改变它的和。
5.2.7 本节小结
级数的判敛与求和
本节把无穷求和化为部分和的极限。判敛工具按适用对象分成两组:正项级数用比较、极限比较、比值、根值、积分判别与 Cauchy 凝聚判别,一般项级数用 Leibniz、Abel、Dirichlet 判别。比值与根值判别只对几何型衰减有效,在
级数处理的是「无穷多个数相加」。下一节把极限用到函数上:函数在某点的极限、连续性的定义与性质,以及连续函数在闭区间上的三条基本定理。那里出现的 ε-δ 语言与本节定义级数收敛时使用的 ε-N 语言结构相同,区别只在于控制的变量从下标换成了点的距离。
练习题
第 1 题 概念推导
(a) 用 Stolz 定理求
参考答案
(a) 取
令
因此
(b) 设
两端都趋于
(c) 对
第 2 题 计算推理
判断下列级数的收敛性并说明理由:(a)
参考答案
(a) 发散。用 Cauchy 凝聚判别:
调和级数发散,因此原级数发散。也可以用积分判别:
(b) 收敛。用比值判别:
(c) 收敛,且收敛很快。比值判别给出
(d) 条件收敛。
误差估计:Leibniz 判别给出余项不超过下一项,
第 3 题 代码验证
用本节代码做三组实验并解释:(a) 把 Aitken 外推的起点从
参考答案
(a) 三组起点对应的误差(对照同位置直接求和的误差):
Aitken 用 n = (9, 10, 11): 结果 = 0.693253968254, 误差 = 1.068e-04, 同位置直接误差 = 4.340e-02
Aitken 用 n = (99, 100, 101): 结果 = 0.693147303688, 误差 = 1.231e-07, 同位置直接误差 = 4.926e-03
Aitken 用 n = (997, 998, 999): 结果 = 0.693147180686, 误差 = 1.256e-10, 同位置直接误差 = 5.002e-04三组的改善倍数约为
(b) 升序朴素求和的相对误差数据:
n = 1000: 升序误差 = 1.776e-15, 相对误差 = 2.373e-16
n = 10000: 升序误差 = 3.375e-14, 相对误差 = 3.448e-15
n = 100000: 升序误差 = 9.237e-14, 相对误差 = 7.640e-15
n = 1000000: 升序误差 = 7.354e-13, 相对误差 = 5.110e-14
n = 10000000: 升序误差 = 2.579e-12, 相对误差 = 1.545e-13相对误差从
(c) 把目标改为
重排目标 2.0: 前 400000 项部分和 = 1.999963, 用正项 392806 个, 负项 7195 个部分和仍然收敛,这次到
第 4 题 综合应用
某程序需要计算一个条件收敛的交错级数到相对精度
参考答案
截断与加速:通项按
浮点实现:累加时用 Kahan 补偿求和或分块求和(若语言提供 fsum 之类的正确舍入求和则直接用),避免朴素逐项升序累加;外推公式中出现相邻部分和之差,这些差本身很小,要留意灾难性抵消:把三个部分和存为双精度并做差时有效数字损失约
可信度验证:三条独立证据。第一,外推结果在不同截断位置应当一致:分别在
代价对比:不用加速时需要约
常见错误
错误 1 · 用通项趋于零判断级数收敛
原因:
解决:判断收敛用判别法(比较、比值、根值、积分、凝聚判别),通项趋于零只用来快速排除明显发散的级数。实现中把停止条件写成余项估计而不是通项阈值:几何级数用
错误 2 · 在条件收敛的级数上随意改变求和顺序
原因:绝对收敛的级数可以任意重排,条件收敛的级数重排后可以收敛到任意值(Riemann 重排定理,本节实验四把交错调和级数重排到
解决:先判定级数是绝对收敛还是条件收敛(检查
错误 3 · 用比值或根值判别处理幂次级数时得出错误结论
原因:这两种判别法在
解决:记住判别法的适用边界(几何型衰减),遇到幂次或对数型通项改用积分判别、凝聚判别或直接比较。实践中的做法是先判断通项属于哪一类衰减(几何、幂次、对数幂次),据此选择判别法;通项里同时出现幂与对数时,用凝聚判别把问题化为纯幂次形式,或与
错误 4 · 直接相减计算接近的数,或用朴素升序累加长序列
原因:两类浮点误差。其一,
解决:相减之前先做代数化简(把差值写成乘积或通分形式),或者用展开式处理小量(math.fsum)、补偿求和(Kahan)或分块求和,避免逐项升序累加;把绝对值小的项放在前面也能改善精度(实验三中降序求和的误差比升序低一个数量级)。