5.1 实数、完备性与极限的语言
数学分析研究的是不断逼近这件事。求曲线下的面积,做法是把区域切成许多细条再求和,细条越窄结果越准;求瞬时速度,做法是先算一段时间的平均速度,再把时间段压到零;迭代算法一步步逼近最优解,问的是误差会不会趋于零。这些过程都在追问同一个问题:一串数(或一串状态)不断变化,它最终会不会稳定到某个值。
讨论这个问题之前,需要先说清它建立在什么样的数系上。有理数在数轴上处处稠密:任意两个有理数之间还有有理数。看起来这已经足够密,但如果只用有理数做极限,会撞上两个麻烦。第一,有些应该存在的极限点不在有理数里,例如用二分法逼近的
本节按这条线索展开:先看清有理数的缺口,再引入实数系的完备性,用它的直接推论(确界原理)证明几个常用结论;然后建立数列极限的严格语言与完备性的六条等价定理;接着把数轴上的开集、闭集、紧性这些概念整理出来,为后面的连续与微分做准备;最后把极限从数轴搬到一般的度量空间,得到压缩映射原理,它是迭代类算法收敛性分析的标准工具。
5.1.1 有理数的缺口
有理数是什么
有理数是能写成分数
稠密性容易让人以为有理数已经把数轴填满了。事实并非如此,数轴上有大量的洞,第一个著名的例子是
一个不存在的有理数
用反证法可以证明
这个结论的几何含义是:边长为
逼近序列的极限不在有理数中
用二分法构造一串有理数来逼近
如果只有有理数,这两个数列是没有极限的收敛数列:数列的项越来越挤在一起,却找不到一个有理数作为它们的极限。第 5.1.4 节的 Cauchy 收敛准则把越来越挤在一起这件事写成了判据,在有理数里这条判据不成立(存在满足判据却没有有理极限的数列),在实数里它成立。这一差别就是完备性的内容。
5.1.2 实数系与确界原理
实数的三组性质
实数系
域性质:加法与乘法的交换律、结合律、分配律成立,有加法单位元
序性质:任意两个实数可以比较大小,这个序与运算相容(
完备性:
第三组性质是有理数缺失的那一条。从直觉上说,完备性把数轴上所有的洞补上了。收紧了这一点之后,才能谈论一个非空有界集合一定有最大值或上确界这类结论,进而得到连续函数的介值定理、最值定理这些基础结果。
实数的构造
公理化描述可以换成显式构造。两种标准做法是:把实数定义为有理数的 Dedekind 分割(把有理数分成左右两半,左半没有最大元),或者定义为一族有理数 Cauchy 列的等价类(两列之差趋于零时视为同一实数)。两种构造都满足上面三组性质,得到的实数系在同构意义下唯一。初学阶段记住一句话就够:实数是有理数的所有可能极限点的补全。
上界与上确界
设
上确界的定义可以写成两条性质:
几个例子:
确界原理:
确界原理的三个常用推论
Archimedes 性质:对任意实数
有理数的稠密性:任意两个实数
5.1.3 数列极限的语言
ε-N 定义
数列
记作
定义里的两句话分别控制两件事。
用定义证明两个例子
例 1:证明
任给
例 2:证明
先估计差值:
这两例展示了标准套路:先把待控制量与极限值的差整理成一个关于
基本性质
四条性质最常用,都可以由定义直接推出。
唯一性:收敛数列的极限唯一。若
有界性:收敛数列有界。取
四则运算:若
夹逼定理:若
什么时候可以先看趋势再补证明
数学分析的推理顺序是先有定义、后有结论,而实际解题顺序常常相反:先用小规模数值实验(代入
5.1.4 完备性的六条等价定理
实数系的完备性有六种常用表达,它们在实数系内互相等价,各自在不同场景下方便使用。
确界原理:非空有上界的实数集有上确界。用于证明根的存在性、连续函数的最值定理与介值定理。
单调有界定理:单调递增且有上界的数列收敛(单调递减且有下界的数列同理)。用于处理递推数列,例如
区间套定理:若闭区间列
Bolzano-Weierstrass 定理:有界数列必有收敛子列。用于从有界序列中挑出收敛的部分,紧性与序列紧性的讨论都围绕它展开。
Cauchy 收敛准则:数列收敛的充要条件是它满足 Cauchy 条件,即对任意
有限覆盖定理:闭区间
六条定理的常用分工可以记成一张表:要证明某个值存在(根、最值、极限)用确界原理或区间套;处理递推数列用单调有界;从有界序列中提取收敛子列用 Bolzano-Weierstrass;判断收敛而不知道极限用 Cauchy 准则;从局部过渡到整体用有限覆盖。它们两两等价的证明常见做法是串成一条链(确界原理导出单调有界,单调有界导出区间套,区间套导出 Bolzano-Weierstrass,Bolzano-Weierstrass 导出 Cauchy 准则,Cauchy 准则导出确界原理),再补上有限覆盖定理与其他定理的等价。
Cauchy 条件与相邻项差趋于零的差别
Cauchy 条件要求任意两项充分靠后时都接近,写成下标是
5.1.5 实数直线的拓扑
极限与连续的概念都可以用开集重新表述,这套语言在多元分析与测度论中成为主要表述方式。
邻域与开集:点
闭集:集合
内点、聚点与边界:点是集合
紧性:集合
连通性:实数轴上的连通集恰好是区间。连通性使介值定理成立:连续函数把区间映成区间,因而在函数值取到两个数之后,中间的数也会被取到。
5.1.6 度量空间与压缩映射原理
度量空间
许多收敛性问题与数轴无关,只依赖距离的定义。度量空间是一个集合
三个例子:实数轴取
度量空间中,数列收敛、Cauchy 列、完备性的定义与数轴上完全一样,只需把绝对值换成距离:
压缩映射原理
定义:映射
常数
定理(压缩映射原理):完备度量空间
证明。先证迭代序列是 Cauchy 列。由压缩性反复使用得
右端随
再证
最后证唯一性。若
与迭代算法的联系
压缩映射原理给出了迭代算法收敛性的通用模板,其中的三个部件在具体问题中分别对应不同的数学事实:压缩性(由函数的导数界或 Lipschitz 常数提供)、完备性(由问题所在的函数空间提供)、不动点(由问题的方程提供)。公式中的误差估计还说明收敛速度是几何速率:每迭代一次,误差至少缩小
与最优化一章的接口
第三章讨论的梯度下降需要假设目标函数的梯度 Lipschitz 连续,这个假设保证迭代映射
5.1.7 数值实验
实验一:二分法与区间套
用二分法求
import math
lo, hi = 0.0, 2.0
for k in range(1, 61):
mid = (lo + hi) / 2
if mid * mid < 2:
lo = mid
else:
hi = mid
if k in (1, 5, 10, 20, 30, 40, 45, 50, 53, 60):
print(f"k = {k:>2}: 区间长度 = {hi - lo:.3e}, 中点 = {mid:.17f}, "
f"相对误差 = {abs(mid - math.sqrt(2)) / math.sqrt(2):.3e}")输出:
k = 1: 区间长度 = 1.000e+00, 中点 = 1.00000000000000000, 相对误差 = 2.929e-01
k = 5: 区间长度 = 6.250e-02, 中点 = 1.43750000000000000, 相对误差 = 1.647e-02
k = 10: 区间长度 = 1.953e-03, 中点 = 1.41601562500000000, 相对误差 = 1.274e-03
k = 20: 区间长度 = 1.907e-06, 中点 = 1.41421318054199219, 相对误差 = 2.700e-07
k = 30: 区间长度 = 1.863e-09, 中点 = 1.41421356238424778, 相对误差 = 7.886e-12
k = 40: 区间长度 = 1.819e-12, 中点 = 1.41421356237151485, 相对误差 = 1.117e-12
k = 45: 区间长度 = 5.684e-14, 中点 = 1.41421356237304963, 相对误差 = 3.219e-14
k = 50: 区间长度 = 1.776e-15, 中点 = 1.41421356237309404, 相对误差 = 7.850e-16
k = 53: 区间长度 = 2.220e-16, 中点 = 1.41421356237309515, 相对误差 = 0.000e+00
k = 60: 区间长度 = 2.220e-16, 中点 = 1.41421356237309492, 相对误差 = 1.570e-16两个现象。区间长度按
第二个现象是浮点数的限制。第
实验二:三种迭代的误差序列
同一个求不动点的目标,三种迭代的误差下降方式完全不同:线性压缩、Newton 迭代、以及一个不满足压缩条件的迭代。
import math
# (a) 线性压缩:h(x) = 0.5x + 1,不动点 2,压缩常数 0.5
x = 1.0
err_a = []
for k in range(12):
err_a.append(abs(x - 2.0))
x = 0.5 * x + 1.0
print("线性压缩 h(x) = 0.5x + 1(不动点 2):")
print(" 误差序列:", " ".join(f"{e:.3e}" for e in err_a))
print(" 相邻误差比值:", " ".join(f"{err_a[i+1]/err_a[i]:.4f}" for i in range(6)))
# (b) Newton 迭代求解 sqrt(2)
x = 1.0
err_b = []
for k in range(8):
err_b.append(abs(x - math.sqrt(2)))
x = (x + 2.0 / x) / 2.0
print("Newton 迭代 f(x) = (x + 2/x)/2(不动点 sqrt(2)):")
print(" 误差序列:", " ".join(f"{e:.3e}" for e in err_b))
print(" 误差平方比值:", " ".join(f"{err_b[i+1]/err_b[i]**2:.4f}" for i in range(4)))
# (c) 非压缩迭代:g(x) = x + 0.5(x^2 - 2),在 sqrt(2) 处导数大于 1
x = 1.5
seq = []
for k in range(10):
seq.append(x)
x = x + 0.5 * (x * x - 2.0)
print("非压缩迭代 g(x) = x + 0.5(x^2 - 2):")
print(" 迭代值:", " ".join(f"{v:.4f}" for v in seq))输出:
线性压缩 h(x) = 0.5x + 1(不动点 2):
误差序列: 1.000e+00 5.000e-01 2.500e-01 1.250e-01 6.250e-02 3.125e-02 1.562e-02 7.812e-03 3.906e-03 1.953e-03 9.766e-04 4.883e-04
相邻误差比值: 0.5000 0.5000 0.5000 0.5000 0.5000 0.5000
Newton 迭代 f(x) = (x + 2/x)/2(不动点 sqrt(2)):
误差序列: 4.142e-01 8.579e-02 2.453e-03 2.124e-06 1.595e-12 2.220e-16 2.220e-16 2.220e-16
误差平方比值: 0.5000 0.3333 0.3529 0.3535
非压缩迭代 g(x) = x + 0.5(x^2 - 2):
迭代值: 1.5000 1.6250 1.9453 2.8374 5.8629 22.0500 264.1515 35151.1559 617837031.9770 190861299658937728.0000三种情形的差别可以由压缩映射原理统一解释,只是压缩常数不同。
线性压缩的误差每步严格减半,比值恒为
Newton 迭代的误差没有固定比例,它按平方规律缩小:误差平方比值稳定在
非压缩迭代在几步之内发散,
实验三:Cauchy 判据与浮点数
Cauchy 判据要求任意两项充分靠后时都接近,比相邻两项接近强得多。调和级数与平方倒数和给出两组对照数据。
def harm(n):
s = 0.0
for k in range(1, n + 1):
s += 1.0 / k
return s
def inv_sq(n):
s = 0.0
for k in range(1, n + 1):
s += 1.0 / (k * k)
return s
print("调和级数部分和(发散):")
for n in [100, 1000, 10000, 100000, 1000000]:
print(f" n = {n:>8}: s_n = {harm(n):.6f}, s_n - s_{{n/2}} = {harm(n) - harm(n // 2):.6f}")
print("平方倒数和部分和(收敛到 pi^2/6 = 1.6449340668):")
for n in [100, 1000, 10000, 100000, 1000000]:
print(f" n = {n:>8}: s_n = {inv_sq(n):.10f}")
print("浮点数与实数:")
print(" 0.1 + 0.2 - 0.3 =", 0.1 + 0.2 - 0.3)
print(" 0.1 + 0.2 == 0.3:", 0.1 + 0.2 == 0.3)
print(" 1 + 1e-16 == 1:", 1 + 1e-16 == 1)输出:
调和级数部分和(发散):
n = 100: s_n = 5.187378, s_n - s_{n/2} = 0.688172
n = 1000: s_n = 7.485471, s_n - s_{n/2} = 0.692647
n = 10000: s_n = 9.787606, s_n - s_{n/2} = 0.693097
n = 100000: s_n = 12.090146, s_n - s_{n/2} = 0.693142
n = 1000000: s_n = 14.392727, s_n - s_{n/2} = 0.693147
平方倒数和部分和(收敛到 pi^2/6 = 1.6449340668):
n = 100: s_n = 1.6349839002
n = 1000: s_n = 1.6439345667
n = 10000: s_n = 1.6448340718
n = 100000: s_n = 1.6449240669
n = 1000000: s_n = 1.6449330668
浮点数与实数:
0.1 + 0.2 - 0.3 = 5.551115123125783e-17
0.1 + 0.2 == 0.3: False
1 + 1e-16 == 1: True调和级数的数据是相邻项差趋于零但序列不收敛的量化版本。相邻两项之差是
平方倒数和的行为相反:从
最后三行说明浮点数与实数的区别。
5.1.8 本节小结
从欠缺到完备
本节从有理数的缺口出发建立了实数系与极限的语言。有理数稠密但有洞,
极限的语言建立之后,下一节用它处理无穷求和:级数的收敛判别、条件收敛的重排现象、以及数值求和中的误差控制。那里出现的渐近记号与收敛速度概念,是后面每一节都要使用的工具。
练习题
第 1 题 概念推导
用 ε-N 定义证明下列极限,并说明
参考答案
(a) 先整理差值:
任给
(b) 对
任给
(c) 相邻项差趋于零只控制下标相差
差值不小于
第 2 题 计算推理
(a) 求集合
参考答案
(a)
(b)
(c)
要求
第 3 题 代码验证
用本节代码做三组实验并解释:(a) 把二分法的循环上限从
参考答案
(a) 循环上限提高后,区间长度仍然停在
(b) 初始值
(c)
差值随
第 4 题 综合应用
某个迭代算法用来求解方程
参考答案
空间与完备性:取
压缩常数:由中值定理,对任意
收敛与速率:
步数估计:最坏的初始误差
监控指标:一是相邻两次迭代的差
两种变化:
常见错误
错误 1 · 用相邻两项的差趋于零判断收敛
原因:这只用到下标相差
解决:判断收敛用 Cauchy 条件(任意
错误 2 · 忘记验证不动点所在的集合是完备的
原因:压缩映射原理要求空间完备。把迭代限制在开区间或无界集合上使用时结论可能失效:空间不完备时 Cauchy 列可能收敛到空间外的点,不动点也可能落在空间之外。用函数把区间映入自身这一条件时,也要逐个验证,否则迭代可能一步跨出区间。
解决:用实数轴上的闭区间(有界闭集完备,且只要验证端点处的取值满足
错误 3 · 把浮点数的行为当作实数的性质
原因:双精度浮点数只有约
解决:把理论结论与数值实现分开评估。设定收敛阈值时不低于机器精度的合理倍数(例如相对误差
错误 4 · 把上确界与最大值混为一谈
原因:上确界是最小的上界,可以不属于集合(例如
解决:使用上确界时明确写出两条性质(本身是上界;对任意