# 多项式插值与 Runge 现象 · 高次不是越准

> 给一堆点，穿过它们的多项式唯一存在。但一个惊人的反直觉：在等距点上用高次多项式插值，边缘会剧烈震荡，点越多越糟——这就是 Runge 现象。这一章用代码复现它，并给出两条解药。

- 作者：David（道雾轩）
- 专栏：数值计算的艺术（https://daiw.org/manual/numerical-computing.md）
- 最后更新：2026-07-14
- 原文：https://daiw.org/manual/numerical-computing/interpolation
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 多项式插值与 Runge 现象 · 高次不是越准

进入第四站：**逼近**。问题很日常——手上有一堆离散的点 $(x_i, y_i)$（实验测量、采样数据），怎么「连成」一条能求任意点值的曲线？这一章讲最经典的**多项式插值**，以及它一个会颠覆直觉的著名陷阱。

## 插值：穿过每一个点

**插值（interpolation）** 要求曲线**精确穿过每一个给定点**。多项式插值有个漂亮的定理：**$n$ 个点，存在唯一的一条 $n-1$ 次多项式穿过它们全部。** 2 个点定一条直线，3 个点定一条抛物线，以此类推。

```python
import numpy as np

xs = np.array([0., 1., 2., 3.])
ys = np.array([1., 2., 0., 5.])
p = np.polyfit(xs, ys, len(xs) - 1)     # 3 次多项式,穿过 4 个点
print(np.polyval(p, xs))                # [1. 2. 0. 5.] —— 精确还原
print(np.polyval(p, 1.5))               # 插值求 x=1.5 处的值
```

看起来很美：点越多、多项式次数越高，应该拟合得越准吧？——**恰恰相反。**

## Runge 现象：点越多，边缘越崩

拿一个看着人畜无害的函数 $f(x)=\dfrac{1}{1+25x^2}$，在 $[-1,1]$ 上取**等距**点做高次插值，看误差随点数怎么变：

```python
f = lambda x: 1 / (1 + 25 * x**2)
xx = np.linspace(-1, 1, 400)            # 密网格,用来量误差

for n in [5, 11, 21]:
    xs = np.linspace(-1, 1, n)          # n 个等距节点
    p = np.polyfit(xs, f(xs), n - 1)    # n-1 次插值多项式
    err = np.max(np.abs(np.polyval(p, xx) - f(xx)))
    print(f"n={n:2d} 个点: 最大误差 = {err:.2f}")
```

```text
n= 5 个点: 最大误差 = 0.44
n=11 个点: 最大误差 = 1.92     ← 变大了!
n=21 个点: 最大误差 = 59.82    ← 爆炸!
```

**点越多，误差越大，而且大得离谱。** 21 个点时，插值多项式在区间**边缘剧烈震荡**，误差高达 60（而函数本身值域只在 $[0,1]$）。这就是 **Runge 现象**：**等距点上的高次多项式插值，会在两端疯狂摆动，且越高次越糟。**

<Callout type="warn">
  **Runge 现象的教训：「用更高次多项式穿过更多点」是个陷阱。** 高次多项式为了精确穿过每一个等距点，不得不在点与点之间（尤其边缘）大幅扭动。这不是舍入误差、也不是[病态](https://daiw.org/manual/numerical-computing/conditioning)——是**等距高次插值这件事本身**的数学性质。所以现实中，**几乎没人用高于三四次的多项式做插值**。「拟合不好就加高次数」的直觉，在这里是错的。
</Callout>

## 解药一：换节点（Chebyshev）

Runge 现象怪的是**等距**节点。如果把节点**在两端加密**（中间稀、边缘密），震荡就被压住了——这种特殊分布叫 **Chebyshev 节点**：

```python
for n in [11, 21]:
    k = np.arange(n)
    xs = np.cos((2*k + 1) * np.pi / (2*n))   # Chebyshev 节点:两端密集
    p = np.polyfit(xs, f(xs), n - 1)
    err = np.max(np.abs(np.polyval(p, xx) - f(xx)))
    print(f"n={n} Chebyshev 节点: 最大误差 = {err:.4f}")
# n=11: 0.10   n=21: 0.017   ← 现在点越多越准了!
```

同样是高次多项式，只是**换了节点分布**，误差就从爆炸变成了随点数稳步下降。**问题不在多项式，在你怎么选点**——这是数值逼近里一个深刻又实用的洞见。

## 解药二：别用高次，用分段（样条）

Chebyshev 要求你能**自由选采样点**——但很多时候点是**给定的**（实验数据就在那些 $x$ 上），你没法换。这时更通用的解法是：**放弃「一条高次多项式管全局」，改用「一段段低次多项式拼起来」**——这就是**样条（spline）**，下一章的主角。它天然免疫 Runge 现象。

## 小结与下一章

多项式插值：$n$ 个点唯一确定 $n-1$ 次多项式穿过它们。但**等距高次插值有 Runge 现象**——边缘剧烈震荡、点越多越崩，是插值本身的数学陷阱，不是误差问题。两条解药：**换 Chebyshev 节点**（两端加密，若能自由选点），或**用分段低次的样条**（点给定时的通用解）。**「加高次数」是插值里最常见的错误直觉。**

既然高次多项式这么危险，那「一段段低次拼接」的样条就成了插值的主力。而且，当数据**带噪声**时，我们甚至**不该**穿过每个点（那是在拟合噪声）——该用最小二乘去「近似」。这两件事，下一章一起讲。👉 [样条与最小二乘：分段的智慧与超定拟合](https://daiw.org/manual/numerical-computing/splines-lsq)。

## 参考文献

- [1] Trefethen.《Approximation Theory and Approximation Practice》—— Runge 现象与 Chebyshev 节点权威。
- [2] Burden & Faires.《Numerical Analysis》, §3.1-3.2 —— 多项式插值。
- [3] NumPy 文档.「numpy.polyfit / polyval.」https://numpy.org/doc/stable/ —— 多项式拟合与求值。
