☰
数值分析第三版答案手册:13章知识地图与误差收敛稳定性复习清单
2026/10/27 2:01:08 网站建设 项目流程

简介:Timothy Sauer《Numerical Analysis(Third Edition)》的英文教师解答手册,面向使用该教材学习数值方法的高校学生、助教与授课教师,用于对照教材习题检查推导过程、核对数值结果并补充解题思路。压缩包共1个PDF文件,大小约6.75MB,内容按教材章节编排,涵盖第0章基础、第1章解方程、第2章方程组、第3章插值、第4章最小二乘、第5章数值微分与积分、第6章常微分方程及第7章边值问题。具体涉及二分法、固定点迭代、牛顿法、高斯消元与LU/PA=LU分解、Chebyshev插值与三次样条、QR分解、Romberg积分、Runge-Kutta方法等,每章配有对应习题解答,便于定位薄弱环节、复盘误差来源并验证程序输出。读者可借助逐题解答理解算法收敛性、稳定性与误差分析,也可与课堂讲义、编程作业相互印证。目前已有3381人学习下载,适合课程作业订正、考前复习和算法实现对照。

1. 一份答案手册背后真正该记的东西

数值分析第三版的答案手册摊开看是一叠解题步骤,合起来其实是一张 13 章的知识地图:从浮点数怎么存、多项式怎么算,到方程求根、线性系统、插值与最小二乘、数值微积分、常微分与偏微分方程,最后收到 FFT、压缩、特征值与优化。学这门课最容易踩的坑,是把每章当成独立题型去背,换个包装就认不出该用哪套工具。这份笔记按三条主线重排——误差从哪来、算法收敛靠什么条件、复杂度与稳定性怎么权衡,适合正在系统学的人建立地图,也适合考前定位薄弱环节。

2. 基础与方程求根:从机器精度到收敛阶

2.1 嵌套乘法:一个被低估的起步动作

多项式求值看起来是最没技术含量的一节,但它决定了后面所有算法误差分析的基调。把P(x) = a0 + a1x + ... + anx^n改写成a0 + x(a1 + x(a2 + ...)),乘法次数从约n^2/2降到n,加法也是n次。这个改写不只是快,中间量更少,累加的舍入误差也更可控。如果多项式是以基点形式给出的(比如插值里的牛顿形式),嵌套写法是c1 + (x-r1)(c2 + (x-r2)(c3 + ...)),代价是n次乘法加2n次加法。

def horner(coeffs, x): # coeffs 按升幂排列:a0, a1, ..., an acc = coeffs[-1] for a in reversed(coeffs[:-1]): acc = acc * x + a return acc # 例:P(x) = 1 + x(2 + x(3 + x(4))) 的系数是 [1, 2, 3, 4] print(horner([1, 2, 3, 4], 0.5)) # 1 + 0.5*(2 + 0.5*(3 + 0.5*4))

这段代码只有一个循环变量和一个累加器,参数coeffs的顺序必须和公式一致,写反了结果不会报错、只会错得很安静。实际操作里最容易翻车的是系数长度和次数对不上:n次多项式需要n+1个系数,缺项要补 0,比如x^3 - 1应该写成[-1, 0, 0, 1]。教材里那些“用嵌套乘法计算并比较误差”的计算机习题,本质是在提醒一件事:同一个数学表达式,不同计算顺序在浮点下不是等价的。

2.2 IEEE 754 双精度:机器精度不是一个玄学数字

双精度浮点数由三段组成,理解这三段是后面所有误差估计的地基。

组成位数含义
符号位 s10 为正,1 为负
阶码 e11实际指数为e - 1023
尾数 f52规格化数隐含前导 1,实际有效位 53 位

由此得到几个必须背下来的常数:机器精度ε_mach = 2^-52 ≈ 2.22e-16,它刻画的是 1 附近相邻两个浮点数的间距;最大规格化数约1.8e308,最小规格化数约2.2e-308,再往下是次规格化数,精度会逐渐掉光。最近舍入规则要说清楚:看第 53 位,为 0 就舍、为 1 就入,如果恰好是1000...这种平局情况,取偶数尾数。这条“取偶”规则在大量累加时会影响最后几位,写数值实验时值得留意。

十进制小数转二进制是这一节的常见考法:整数部分除 2 取余、倒序排列,小数部分乘 2 取整、顺序排列。像0.1这种十进制有限小数,在二进制里是无限循环的,所以fl(0.1)从存储那一刻就带了相对误差约1e-17的偏差,这也是0.1 + 0.2 != 0.3的根源。

2.3 有效数字丢失:减法才是精度杀手

很多人以为浮点误差来自“除不尽”,实际最常见的翻车点是两个相近数相减。经典的二次求根公式x = (-b ± sqrt(b^2 - 4ac)) / (2a),当b^2远大于4ac时,-b + sqrt(b^2-4ac)这一支会发生严重抵消,有效数字成片消失。稳定写法是把它改写成x1 = (-b - sqrt(b^2-4ac)) / (2a),另一根用韦达定理x2 = c / (a * x1)求,避免直接相减。

同类问题还有几个固定套路,复习时可以直接当清单用:

  • 1 - cos(x)在x很小时改写为2 * sin(x/2)^2。
  • e^x - 1在x接近 0 时用expm1(x)。
  • log(1 + x)在x很小时用log1p(x)。
  • 大数加小数再减大数,顺序一换结果就变,能合并的先合并。

这一类改写背后的判断标准是相对误差而不是绝对误差。绝对误差1e-16对1.0可以忽略,对1e-20就是灾难。梳理下来会发现,教材把“损失有效数字”单独列一节,是因为它直接决定了后面牛顿法、差商、数值微分里步长怎么选。

提示:判断是否发生抵消,看运算结果的有效位数是否远小于输入的有效位数,而不是看结果绝对值大小。

2.4 二分、不动点、牛顿与割线:收敛阶对照表

方程求根是第一个完整的算法模块,四种方法的差别必须能一张表说清。

方法收敛阶每步需要成立前提典型失效场景
二分法线性,误差每步减半1 次函数求值端点函数值异号区间内有偶数个根;浮点下区间无法再分
不动点迭代线性,比率约 `g'(r)`1 次迭代函数求值
牛顿法二次f与f'各一次f'(r) ≠ 0,初值足够近重根降为线性;导数为 0 附近直接飞出去
割线法超线性,阶约 1.6181 次函数求值两个较好初值分母接近 0 时数值不稳

二分法的迭代次数可以直接估:要把区间从b-a缩到tol,需要n ≥ log2((b-a)/tol)步。双精度下大概 52 次左右就会卡在相邻浮点数之间,再分下去区间端点不再变化,这就是教材里“精度极限”那一节要讨论的现象——不是方法失效,是浮点表示到了尽头。

牛顿法的误差递推值得手推一遍:e_{i+1} ≈ (f''(r) / (2f'(r))) * e_i^2。这个式子解释了为什么初值重要(误差被平方放大或缩小)、为什么重根会退化(f'(r) = 0时前面的系数发散,实际降为线性收敛)。割线法用差商代替导数,牺牲一点收敛阶换来不用解析导数,实际工程里更常用;再往上还有逆二次插值和混合策略,思路都是“先用安全方法兜底,接近根时切换成快方法”。

def bisect(f, a, b, tol=1e-12, max_iter=200): fa, fb = f(a), f(b) if fa * fb > 0: raise ValueError("端点必须异号") for _ in range(max_iter): m = 0.5 * (a + b) fm = f(m) if abs(fm) < tol or 0.5 * (b - a) < tol: return m if fa * fm < 0: b, fb = m, fm else: a, fa = m, fm return 0.5 * (a + b) def newton(f, df, x0, tol=1e-12, max_iter=100): x = x0 for _ in range(max_iter): fx, dfx = f(x), df(x) if dfx == 0: raise ZeroDivisionError("导数为零,牛顿法失效") x_new = x - fx / dfx if abs(x_new - x) < tol: return x_new x = x_new return x

两段代码的关键差异在停止条件和安全保障。二分法用区间宽度和函数值双重判断,牛顿法只比较相邻两次迭代的差,这在收敛慢的时候会误判为“已经收敛”,所以生产代码里通常再加一条残差判据abs(f(x)) < tol。参数tol不要设到比ε_mach还小,否则循环永远达不到,白白跑满迭代次数。

3. 线性系统、最小二乘与特征值:矩阵这条主线

3.1 高斯消元与 PA=LU:为什么必须换行

高斯消元的代价是(2/3)n^3 + O(n^2)次乘除,前代和回代各O(n^2)。手算时没人关心这个数,但它是判断“能不能直接解”的唯一依据:n = 10000时n^3量级已经到了普通机器扛不住的程度,这才有了后面的迭代法。

不选主元的高斯消元在遇到主元为 0 时直接崩,遇到主元很小时误差被放大。部分主元法每次选当前列绝对值最大的行交换上来,把乘数控制在 1 以内。写成矩阵形式就是PA = LU,其中P是置换矩阵、L是单位下三角、U是上三角。这个分解的复用价值在于:同一个系数矩阵、多个右端项时,分解一次就能反复前代回代,代价从每次O(n^3)降到O(n^2)。

import numpy as np def lu_partial_pivot(A): A = A.astype(float).copy() n = A.shape[0] P = np.eye(n) L = np.zeros((n, n)) for k in range(n - 1): p = k + np.argmax(np.abs(A[k:, k])) # 选列主元 if abs(A[p, k]) < 1e-15: raise ValueError("矩阵接近奇异") if p != k: A[[k, p], :] = A[[p, k], :] P[[k, p], :] = P[[p, k], :] L[[k, p], :k] = L[[p, k], :k] # 已算出的乘数也要跟着换 for i in range(k + 1, n): L[i, k] = A[i, k] / A[k, k] A[i, k:] -= L[i, k] * A[k, k:] L += np.eye(n) return P, L, np.triu(A)

这段实现里最容易漏的是“交换行时L已经算出的那部分也要换”,漏了就会得到一个看起来像模像样、代入验证却不满足PA = LU的结果。参数上没有需要调的东西,但阈值1e-15是经验值,判断奇异更稳妥的做法是比较主元与矩阵范数的比值。

3.2 误差来源与条件数:残差小不等于解得对

线性系统这一块最重要的概念是条件数。对方程组Ax = b,右端扰动带来的相对误差满足||δx|| / ||x|| ≤ cond(A) * ||δb|| / ||b||,其中cond(A) = ||A|| * ||A^-1||。这句话的信息量很大:条件数放大的是相对误差,不是绝对误差;条件数只和矩阵有关,和用什么算法无关。

一个必须纠正的直觉是“残差小说明解对”。残差是r = b - A x_hat,它衡量的是x_hat代回方程后差多少,而误差是x_hat和真解的差距。对病态矩阵,完全可能残差只有1e-14而解的误差在第一位有效数字上。经典例子是希尔伯特矩阵,n = 12左右条件数就上了1e16,双精度基本解不动。

误差来源这一节通常分三类:数据本身的误差(建模、测量)、舍入误差(浮点表示)、算法误差(截断、消元过程中的增长因子)。向后误差分析给出的结论是“高斯消元配部分主元是向后稳定的”,但它只保证解是某个邻近问题的精确解,不保证离原问题近。所以复习时要分清:稳定性是算法属性,条件性是问题属性,前者不能弥补后者。

3.3 迭代法与 SPD 矩阵:什么时候不用直接法

直接法代价O(n^3),迭代法每步O(n^2)(稀疏矩阵还能更低),适合大型稀疏系统。Jacobi 迭代把A拆成D - L - U,用x^{k+1} = D^-1 (b + (L+U)x^k);Gauss-Seidel 立刻用上新算出来的分量,通常收敛更快。收敛的充要条件是迭代矩阵的谱半径小于 1,充分条件是矩阵严格对角占优——后者好验证,所以考试里常考。

对称正定矩阵有专门的 Cholesky 分解A = R^T R,代价约(1/3)n^3,是高斯消元的一半,而且不用选主元(对称正定保证了主元恒正)。判断能不能用:先看对称,再看所有顺序主子式是否为正,或者直接试分解,出现负数开根就说明不满足前提。

def cholesky(A): n = A.shape[0] R = np.zeros((n, n)) for i in range(n): for j in range(i + 1): s = A[i, j] - sum(R[i, k] * R[j, k] for k in range(j)) if i == j: if s <= 0: raise ValueError("矩阵不是正定") R[i, j] = np.sqrt(s) else: R[i, j] = s / R[j, j] return R

循环里s <= 0的检查是必须的,它同时承担了“数值上是否还能继续”的判断。实际算的时候,A只读下三角,输出是上三角R,验证方式是和R.T @ R对比,而不是和A直接比。

3.4 最小二乘:正规方程、QR 与非线性版本

最小二乘要解min ||Ax - b||_2,最直接的做法是正规方程A^T A x = A^T b。它的坑在于条件数平方:cond(A^T A) = cond(A)^2,原本cond(A) = 1e8还能勉强算,平方之后直接到1e16,双精度报废。所以正规方程适合教学和良态小问题,实际计算走 QR 分解:A = QR,解Rx = Q^T b,条件数不会被放大。Householder 变换做 QR 的代价约2mn^2 - (2/3)n^3,比正规方程贵一点,但稳得多。

模型综述那一节覆盖了多项式拟合、指数模型、幂律模型,核心技巧是“能线性化的先线性化”,比如y = a e^{bx}取对数变成ln y = ln a + bx。代价是误差的度量方式被改变了(在对数尺度上最小化残差),拟合结果和原始尺度上的最小二乘不完全一样,这个差别在数据跨几个数量级时很明显。

非线性最小二乘用 Gauss-Newton:在当前点线性化残差r(x),解J^T J δ = -J^T r,更新x ← x + δ。J是残差向量的雅可比。它本质上是把正规方程套在每一步的线性化上,所以病态和发散的风险原样继承,Levenberg-Marquardt 加一个阻尼项λI就是为了在“接近二次收敛”和“稳定下降”之间切换。大尺度稀疏问题还会用到 GMRES 这类 Krylov 子空间方法,思路是只在低维子空间里找近似解。

3.5 特征值与 SVD:幂迭代、QR 算法与低秩近似

幂迭代求主特征值,迭代式就是x ← Ax / ||Ax||,收敛比率由|λ2 / λ1|决定。λ2和λ1靠得越近收敛越慢,这个比率是判断“值不值得用幂迭代”的唯一指标。逆幂迭代把A换成(A - σI)^-1,可以收敛到离σ最近的那个特征值;瑞利商迭代动态更新σ,局部可以做到三次收敛。

QR 算法是求全部特征值的标准路线,先化成 Hessenberg 形式降低每步代价,再用移位加速。SVD 是这一章的收尾大招,A = UΣV^T,奇异值是A^T A特征值的平方根,条件数就是σ1 / σn。它的实际价值在低秩近似:只保留前k个奇异值,得到的是所有秩为k的矩阵里在 Frobenius 范数下最近的逼近(Eckart-Young 定理),图像压缩、推荐系统、降噪都建立在这个结论上。伪逆A^+ = VΣ^+U^T则把最小二乘和秩亏问题统一处理了。

def power_iteration(A, num_iter=1000, tol=1e-12): n = A.shape[0] x = np.ones(n) / np.sqrt(n) # 初始向量,避免全零 lam_old = 0.0 for _ in range(num_iter): y = A @ x lam = x @ y # 瑞利商,比 ||y|| 的估计更准 x = y / np.linalg.norm(y) # 归一化,防止溢出 if abs(lam - lam_old) < tol: break lam_old = lam return lam, x

归一化那一步不能省,否则几十次迭代后数值就溢出了。停止条件用的是瑞利商的变化量,比直接比较特征向量更稳。初始向量的选择会影响迭代次数,但不会影响最终收敛到的主特征值——除非初始向量恰好和主特征向量正交,概率极低但理论上存在。

4. 插值、数值微积分与微分方程:从离散点到连续解

4.1 多项式插值、Runge 现象与样条

n+1个互异节点可以唯一确定一个不超过n次的多项式,这是插值的理论起点。误差公式是f(x) - P_n(x) = f^{(n+1)}(ξ) / (n+1)! * ∏(x - x_i),它说明误差由两部分决定:函数的高阶导数和节点乘积项。等距节点插值高次多项式会出现 Runge 现象,典型例子是1/(1+25x^2)在[-1, 1]上,次数越高两端振荡越剧烈。

解决思路有两条。一条是换节点,用 Chebyshev 节点x_k = cos((2k+1)π / (2n+2)),它让节点乘积项的最大值最小化,误差被压到最低,这就是 Chebyshev 插值那一节的核心。另一条是换基函数,用分段低次多项式,三次样条就是代表:它要求C^2连续,每段是三次多项式,整体可以用一个三对角系统O(n)解出来。自然样条额外要求两端二阶导为零,夹持样条则给定端点导数。工程上做曲线,三次样条比高次多项式可靠得多。

Bézier 曲线是另一条路:用 Bernstein 基函数加权控制点,曲线落在控制点凸包内,端点处与控制多边形相切,de Casteljau 算法用反复取中点的方式稳定求值。它不追求插值所有点,追求的是形状可控,这和样条的出发点是不同的。

4.2 数值微分与 Newton-Cotes:步长不是越小越好

数值微分的误差有两个来源,一个是截断误差,随h减小而减小;一个是舍入误差,随h减小而增大(因为f(x+h) - f(x)的抵消越来越严重)。总误差≈ C h^p + ε/h,最优步长约在h ≈ ε^{1/(p+1)}处。

公式表达式截断误差
前向差分(f(x+h) - f(x)) / h-h/2 * f''(ξ)
后向差分(f(x) - f(x-h)) / hh/2 * f''(ξ)
中心差分(f(x+h) - f(x-h)) / (2h)-h^2/6 * f'''(ξ)
二阶中心(f(x+h) - 2f(x) + f(x-h)) / h^2-h^2/12 * f''''(ξ)

中心差分是O(h^2),前向是O(h)。双精度下中心差分的最优步长约1e-5到1e-6,再小反而更差,这个现象在实验里非常直观,也是“误差阶只记结论不记前提”的经典翻车现场。

Newton-Cotes 公式是插值型求积:对节点上的插值多项式积分。梯形公式误差-(b-a)^3/12 * f''(ξ),Simpson 公式误差-(b-a)^5/2880 * f^{(4)}(ξ)。复合形式把区间分成n段,误差分别降到O(h^2)和O(h^4)。

def composite_simpson(f, a, b, n): # n 必须是偶数,表示区间被分成 n 段 if n % 2 != 0: raise ValueError("Simpson 需要偶数段") h = (b - a) / n s = f(a) + f(b) for i in range(1, n): s += (4 if i % 2 == 1 else 2) * f(a + i * h) return s * h / 3

系数4, 2, 4, 2, ...交替出现是 Simpson 公式的结构,写错一次结果偏差会很明显。n必须是偶数,因为每两段构成一个抛物线。实际使用时通常采用“把n翻倍再比较”的方式估计误差,而不是相信理论误差公式,因为四阶导数的界往往估不出来。

4.3 Romberg、自适应与 Gauss 求积

Romberg 积分建立在梯形公式的 Euler-Maclaurin 展开上:误差可以写成h^2的幂级数,于是可以用两次不同步长的结果外推消掉低阶项。做成一整张表就是 Romberg 表,第一列是逐步减半的梯形值,后面每列都是前两列的线性组合。它不需要额外函数求值,纯粹靠已有数据外推,所以在函数求值昂贵的场景里很划算。

自适应求积换个思路:不平均分段,而是递归地比较一段上的粗算和细算结果,误差超过容差就把这段劈成两半继续。这样在函数剧烈变化的地方自动加密,在平缓的地方保持稀疏。

Gauss 求积是另一条路线:既然节点可以自由选,那就选到“n个节点能精确积分2n-1次多项式”为止。这些节点是 Legendre 多项式的根,权重由积分公式解出。n个节点能达到2n-1阶精度,这比等距节点的 Newton-Cotes 高出一倍,代价是节点和权重需要预先查表或现场计算,而且不能像复合公式那样简单地“再分一段”。

4.4 常微分方程:Euler、RK4、刚性与多步法

初值问题y' = f(t, y), y(t0) = y0的数值解法,核心概念是阶数和稳定性。显式 Euler 法y_{n+1} = y_n + h f(t_n, y_n)的局部截断误差是O(h^2),全局是O(h),也就是步长减半、误差减半,效率很低。四阶 Runge-Kutta 每步四次函数求值,全局O(h^4),是默认首选。

def rk4(f, t0, y0, h, steps): t, y = t0, np.array(y0, dtype=float) ts, ys = [t], [y.copy()] for _ in range(steps): k1 = f(t, y) k2 = f(t + h / 2, y + h / 2 * k1) k3 = f(t + h / 2, y + h / 2 * k2) k4 = f(t + h, y + h * k3) y = y + h / 6 * (k1 + 2 * k2 + 2 * k3 + k4) t += h ts.append(t) ys.append(y.copy()) return np.array(ts), np.array(ys)

四个k的系数1/6, 2/6, 2/6, 1/6来自 Simpson 权重,这不是巧合——RK4 的构造和数值积分有直接联系。f的签名必须是f(t, y),y支持向量,这样同一份代码能处理方程组,因为高阶方程化成一阶方程组之后形式完全一样。

稳定性要用测试方程y' = λy分析。显式 Euler 的稳定域是|1 + hλ| ≤ 1,当λ是绝对值很大的负实数(刚性方程),h必须小到不现实,这就是刚性问题。隐式 Eulery_{n+1} = y_n + h f(t_{n+1}, y_{n+1})需要每步解方程,但稳定域覆盖整个左半平面,是无条件稳定的。多步法用前几步的历史值,Adams-Bashforth 是显式、Adams-Moulton 是隐式,预测-校正把两者结合,用显式预测、隐式校正,兼顾效率和稳定。

4.5 边值问题与偏微分方程:打靶、有限差分与稳定性条件

边值问题y'' = f(x, y, y')加两端条件,常见解法有三种。打靶法把未知的初始斜率当成参数,解一系列初值问题,再用求根方法调整参数使右端满足边界条件——本质是把 BVP 转成根问题。有限差分法直接在网格上把导数换成差商,得到一个三对角线性系统,误差O(h^2)。配点法和有限元法用基函数展开,适合复杂区域,代价是要处理弱形式和刚度矩阵组装。

偏微分方程按类型分三块:

类型代表方程显式格式稳定性条件
抛物型热方程r = k / h^2 ≤ 1/2
双曲型波动方程c k / h ≤ 1(CFL 条件)
椭圆型Laplace 方程无时间步,直接解线性系统

热方程的显式格式往前推一步只需要O(n),但r ≤ 1/2意味着空间网格加密一倍,时间步要缩到四分之一,总代价涨得很快。Crank-Nicolson 是隐式的、无条件稳定,每步要解三对角系统,通常更划算。CFL 条件的物理含义是“信息传播速度不能超过网格允许的速度”,写反h和k是这一节最高频的错误。

4.6 变换、压缩与随机模拟:FFT、DCT 与 Monte Carlo

三角插值用正弦余弦函数做基,DFT 直接算是O(n^2),FFT 用分治把代价降到O(n log n),前提是长度取 2 的幂(或者做补零/混合基处理)。这个加速幅度大到改变了工程实践:实时信号处理、频谱分析都建立在它之上。

DCT 是 DFT 的实数版本,能量集中特性好,8×8 分块加量化就是 JPEG 的核心。Huffman 编码做变长前缀码,高频符号用短码,压缩率取决于符号分布;MDCT 用重叠窗消除块边界的不连续,是音频压缩的基础。这一块的知识点是“变换 + 量化 + 熵编码”三段式,考试里常考 DCT 为什么比 DFT 更适合图像压缩。

随机数这章容易被当成选修,但内容很成体系:线性同余生成器产生伪随机序列,Monte Carlo 积分用样本均值近似期望,误差是O(1/√n)——收敛慢,但和维数无关,这是它对抗维数灾难的唯一资本。布朗运动和随机微分方程用 Euler-Maruyama 格式离散,强阶 0.5、弱阶 1.0,阶数定义和确定性 ODE 不一样,考试里经常在这里设陷阱。

5. 易漏点:误差阶、收敛条件与稳定性上最容易翻车的地方

5.1 易漏点一:把“方法收敛”当成“这道题能算对”

为什么漏:定理给的是极限意义下的收敛,条件是“迭代次数趋于无穷”或“初值足够近”,而实际只跑有限步、初值也只是拍脑袋选的。二分法在双精度下会卡在相邻浮点数之间,不动点迭代在|g'(r)|等于 0.99 时每步只缩小 1% 的误差,牛顿法在导数接近 0 时会跳到很远的地方。

怎么补:动手前先做三件事——验证前提(端点异号、导数非零、谱半径小于 1)、估一个迭代次数上限、设一个和ε_mach匹配的容差。跑完再看残差和步长历史,如果步长突然变大或残差不再下降,就是前提被破坏了,不是代码写错了。

5.2 易漏点二:误差阶只记结论,不记前提

为什么漏:O(h^2)这种写法把常数和条件都藏起来了。中心差分是二阶,前提是f三阶连续可导且h落在截断误差主导的区间;h小到1e-10时舍入误差反超,实测误差比一阶的前向差分还大。

怎么补:对任何带步长的公式,做一次log-log误差曲线,看斜率是不是理论阶数,看曲线在哪里拐弯。拐点之前的误差是截断主导,拐点之后是舍入主导,最优点就在中间。这个动作比背结论有用得多。

5.3 易漏点三:条件数与残差混为一谈

为什么漏:残差||b - Ax||在代码里唾手可得,看起来像个现成的正确性指标;条件数要额外算,容易被跳过。病态矩阵上残差可以小到1e-14而解的误差在第一位上。

怎么补:养成“残差 + 条件数”双检查的习惯,用相对误差 ≲ cond(A) * 相对残差估一个上界。如果条件数已经到1e12以上,就别指望双精度能给出 6 位有效数字,要么换问题 formulation,要么上高精度。

5.4 易漏点四:稳定性条件写反或漏掉边界

为什么漏:r = k/h^2和c k/h两个式子里的h、k位置不同,量纲也不一样,记混一次就全错。另外≤ 1/2的等号边界经常被写成<,实际在边界上格式仍然稳定,只是余量消失。

怎么补:用量纲检查——k是时间、h是空间,k/h^2必须无量纲才可能是稳定性判据。再补一个收敛测试:取一个已知解析解,跑几组不同网格,看误差是否按理论阶下降,稳定性条件错的话误差会直接爆掉而不是缓慢增长。

5.5 易漏点五:答案手册的中间步骤对不上,其实是参数没对齐

为什么漏:同一道题在不同版本里编号会变,代码题里的系数个数、初始值、容差也可能不同。照着答案抄一遍能对上,自己动手时函数签名或参数顺序一改,结果就不同,然后怀疑自己理解错了。

怎么补:不要只对照纸面步骤,先把代码跑通,打印中间量(迭代次数、残差序列、矩阵分解结果),和自己的手算逐步对比。对不上的时候优先查三处:系数顺序(升幂还是降幂)、索引起点(0 还是 1)、容差定义(绝对还是相对)。这三处能解释大部分“明明一样却算不出”的情况。

6. 复习清单:把 13 章压成一张能执行的查漏表

考前最有效的动作不是重读一遍,而是按模块做自测。下面这张表把每章压成“必背结论 + 一个可执行动作”,做完打勾,空着的就是薄弱环节。

模块必背结论自测动作
浮点与误差ε_mach = 2^-52,最近舍入取偶,相减抵消手算fl(0.1)的二进制展开前 10 位
方程求根二分线性、牛顿二次、割线 1.618手推牛顿误差递推式,说明重根为何退化
线性系统消元(2/3)n^3,PA=LU,条件数放大相对误差用 3×3 矩阵手算一次带主元的 LU
迭代与 SPD谱半径小于 1 是充要条件,Cholesky 代价减半判断给定矩阵能否 Cholesky 分解
最小二乘正规方程条件数平方,QR 不放大对比两种解法在病态矩阵上的误差
特征值与 SVD幂迭代比率 `λ2/λ1
插值误差含f^{(n+1)}与节点乘积,Chebyshev 压振荡画 Runge 例子,比较等距与 Chebyshev
数值微积分中心差分O(h^2),SimpsonO(h^4),Gauss 精确到2n-1画误差随h变化的 log-log 图
常微分方程EulerO(h),RK4O(h^4),刚性用隐式用同一问题验证 RK4 的收敛阶
边值与偏微分打靶转根问题,FTCSr ≤ 1/2,CFLck/h ≤ 1量纲检查两个稳定性条件
变换与随机FFTO(n log n),Monte CarloO(1/√n)解释 DCT 为何比 DFT 适合图像压缩

最后留一个能直接跑的小实验,用来验证“误差阶”这件事到底是不是真的:

import numpy as np f = np.sin df = np.cos x0 = 1.0 for h in [1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8]: forward = (f(x0 + h) - f(x0)) / h central = (f(x0 + h) - f(x0 - h)) / (2 * h) print(f"h={h:.0e} 前向误差={abs(forward - df(x0)):.3e} 中心误差={abs(central - df(x0)):.3e}")

跑完会看到前向差分的误差随h线性下降,中心差分先按平方下降、到h约1e-8附近开始反弹。反弹那一段就是舍入误差接管了,它比任何公式都更能说明“步长不是越小越好”。

我自己的习惯是:每复习完一章,不急着翻下一章,而是先合上书把这一章的“前提、代价、失效场景”三句话写出来,写不出来的地方就是没真懂。数值分析这门课的血泪经验是,公式记错还能查,前提记错会一路错到底。从那以后我每次做数值题都强制先写一遍前提条件再动笔,正确率比刷题量提升得明显。希望帮到你。

这份笔记对应的完整答案手册已经整理好,按章归档、题号与原书对齐,配合上面的清单逐章过一遍,比漫无目的地翻要省时间得多。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询