2. 数值算法正确性验证基础
在数值计算中,“正确”并不等于“精确”。绝大多数数值算法面对的是浮点数运算、有限次迭代和离散化近似,因此结果必然带有误差。正确性验证的核心任务,不是追求零误差,而是判断误差是否在可接受范围内、是否由可解释的原因产生、以及算法在输入扰动下是否仍然可靠。本节围绕误差来源、条件数与稳定性、前向与后向误差、以及验证基本准则展开,为后续测试用例设计打下概念基础。
一、误差从哪里来:舍入误差与截断误差
数值误差通常分为两大类。第一类是舍入误差,来源于计算机用有限位二进制表示实数。例如 IEEE 754 双精度浮点数只有约 15~17 位有效十进制数字,像 0.1 这样的数无法精确表示,每次加减乘除都可能引入半个机器精度量级的偏差。舍入误差的典型特征是:单次很小,但在大量累加、相减抵消或迭代放大时会显著累积。
第二类是截断误差,来源于用有限过程近似无限过程。例如用泰勒展开的前几项近似函数值、用差商代替导数、用有限步迭代逼近极限。以中心差商近似导数为例:
f'(x) ≈ (f(x+h) - f(x-h)) / (2h)
其截断误差约为 O(h²),h 越小截断误差越小;但 h 过小时,分子中两个相近数相减会产生严重的舍入抵消,舍入误差反而按 O(ε/h) 增大。这说明两类误差往往此消彼长,存在一个“最优步长”,这也是数值算法验证中必须关注的典型现象。
二、条件数与稳定性:问题与算法的两种“敏感度”
条件数描述的是问题本身的敏感程度,与算法无关。对线性方程组 Ax=b,条件数 κ(A)=‖A‖·‖A⁻¹‖。条件数大意味着输入 b 或 A 的微小扰动会被放大成解的巨大变化。例如希尔伯特矩阵随阶数增加条件数急剧增大,即使使用精确算法,解也可能因输入舍入而严重失真。因此条件数告诉我们:这个问题“天生难不难”。
稳定性描述的则是算法在计算过程中是否控制误差增长。一个稳定的算法不会让初始的小误差在迭代中被指数放大。典型例子是递推计算积分 Iₙ=∫₀¹ xⁿ/(x+5)dx,若用正向递推 Iₙ=1/n−5Iₙ₋₁,误差每步被放大 5 倍,很快失控;而改用反向递推,误差每步缩小为 1/5,结果稳定。这说明同一问题换一种算法,稳定性可以完全不同。
三、前向误差与后向误差:从两个方向衡量“算得准不准”
设真实问题为 f(x)=y,计算得到近似解 ŷ。前向误差指 |ŷ−y| 或其相对形式,直接回答“结果离真值多远”。后向误差则反过来问:ŷ 是否是某个轻微扰动问题 f(x+Δx)=ŷ 的精确解?若能找到很小的 Δx 使等式成立,则称算法具有较小的后向误差。
后向误差的价值在于:它把“计算误差”转化为“输入扰动”,从而可以借助条件数估计前向误差,即近似满足
前向误差 ≲ 条件数 × 后向误差
这一关系是数值验证的重要桥梁。若后向误差很小(算法稳定),而前向误差仍然很大,则问题多半出在条件数上,属于问题病态而非算法错误;反之若后向误差本身就大,则算法实现或参数选择存在问题。实际验证时,对无解析解的问题,常用“代入残差”‖Aŷ−b‖ 作为后向误差的代理指标。
四、正确性验证的基本准则
基于上述概念,数值算法正确性验证应遵循几条基本准则。第一,明确参照系与容差:先约定误差是绝对还是相对、以哪个量为基准,再设定与问题条件数和机器精度相匹配的容差,避免“一刀切”的固定阈值。第二,区分误差来源:通过改变步长、迭代次数或精度观察误差变化趋势,判断主导误差是截断还是舍入。第三,同时考察前向与后向指标:有真解时算前向误差,无真解时用残差作后向误差代理。第四,做扰动与收敛性测试:对输入施加小扰动观察输出放大倍数,并与条件数估计对照;对迭代算法检查误差是否随步数单调下降或收敛到稳定水平。
例如验证一个求根迭代时,可记录每步的 |xₖ−x*|(前向误差)与 |f(xₖ)|(残差型后向指标),若残差迅速趋近机器精度而前向误差停滞,往往说明根附近条件数较大或存在多个相近根,需要调整判据而非简单判定算法失败。掌握这些准则,才能在后续设计测试用例时,让每一个用例都对应明确的误差假设与可判读的通过标准。