先说结论
高次多项式插值在两端振荡,常见的解释是"次数太高了"。这个解释不对,或者说只抓到了表象。
真正的原因是三句话:
多项式是全局刚性的。所有系数共同决定每一点的值,你没法只在局部修一修。
区间两端的约束天生不足。内部的点左右都有邻居夹着,两端的点只有单侧邻居,那里的行为更像外推而不是插值。
等间距采样恰好在最需要信息的地方给得最少。
三者叠在一起,误差放大倍数随次数呈2n2^n2n增长。次数一上去就立刻崩。
为什么"次数太高"是个错解释
因为有一个很干脆的反例。
同样的函数、同样的次数,只把采样点改成两端密、中间疏,振荡就消失了。这种摆法叫切比雪夫节点:
xk=cos (kπn)x_k = \cos\!\left(\frac{k\pi}{n}\right)xk=cos(nkπ)
在这个分布下,Runge 函数做到1000 次多项式都能收敛到机器精度。
次数一个字没改。变的只有点的位置。
等间距(11 点)—— 均匀铺开,两端稀疏 ●────●────●────●────●────●────●────●────●────● -1.0 0.0 1.0 ↑ 两端和中间一样稀 ↑ 切比雪夫(11 点)—— 两端挤在一起 ●─●───●─────●───────●───────●─────●───●─● -1.0 0.0 1.0 ↑↑ ↑↑ 两端加密 两端加密所以"次数高"不是病因,它只是把病因放大了。病因是采样分布和多项式的需求不匹配。
全局刚性意味着什么
这是整件事的根。
一个nnn次多项式由n+1n+1n+1个系数完全确定,而每个系数都影响每一点的值。你挪动一个采样点,整条曲线从头到尾都会重排。
这跟分段函数完全不同。分段函数你改一段,别的段不动。多项式没有"段"的概念——它是一个整体,一动全动。
刚性本身不是坏事。坏的是刚性加上约束分布不均。
想象一根钢条,你要把它固定成某个形状。钢条很硬(刚性),你在上面钉了一排钉子。中间的钉子每一颗都被左右邻居协同约束着,位置很确定。但最外侧那两颗钉子,外侧没有任何东西拉住它——钢条在那里可以自由翘起来。
●───●───●───●───●───●───●───●───●───● ↑ ↑ 只有右侧有邻居 只有左侧有邻居 外侧无约束 → 自由翘起 外侧无约束 → 自由翘起钢条越硬(次数越高),翘得越远。
为什么端点处是"外推"
这个说法值得展开一下,因为它解释了为什么问题只出在两端。
插值是在已知点之间求值,外推是在已知点之外求值。外推不稳定是常识。
区间端点的处境很微妙:它在数据范围之内,但邻域有一半在数据范围之外。多项式在那附近的行为,受到的有效约束只有单侧,所以它表现得更接近外推。
区间内部 区间端点 ←─ 数据 ─●─ 数据 ─→ ←─ 数据 ─● (无数据) 双侧约束,稳定 单侧约束,接近外推这就是为什么振荡的位置永远在两端,而且越靠边越厉害。中间那一段其实拟合得很好——误差分布是明确的两极分化,不是整体退化。
所以等间距错在哪
把上面几点连起来,答案就是一句话:
多项式在区间两端需要更密的采样才能被钉住,等间距分布却给了和中间一样的密度。
这是一个供需错配。两端的约束需求最大,供给却和别处相同。
切比雪夫节点做的事就是把供给往需求大的地方调。那个cos\coscos函数本质上是在把均匀分布的角度映射到xxx轴上——角度均匀,投影到直线上就自然两端密、中间疏。
在圆上均匀取角度,投影到 x 轴: ● ● ● ● ● ● ● ● ● ● ● ● ● ● ↓ ↓ ↓ ↓ ↓ ↓ ●─●──●────●────●──●─● ← 两端自动变密不是人为凑的分布,是从几何上自然长出来的。
这个认知的实际用处
知道病因在"分布"而不在"次数",会改变你的处理方式。
如果你能选采样点,就按切比雪夫分布采。这在拟合解析函数、做查找表、预计算光照曲线时都可行。同样的次数,精度提升可以差几个数量级。
如果采样点由别人给定(关卡编辑器里的航点、动画师 K 的关键帧、从设备读来的数据),那你就改不了分布。这时唯一的出路是换方法。
这正是样条存在的理由。
样条怎么绕开这件事
样条没有解决这个问题,它绕开了。
| 高次多项式 | 三次样条 | |
|---|---|---|
| 想更精确 | 升次 | 加段 |
| 次数 | 跟着涨 | 钉死在 3 |
| 刚性 | 全局 | 局部 |
| 会不会振荡 | 会,随次数指数恶化 | 不会 |
| 改一个控制点 | 整条曲线变形 | 只影响邻近两段 |
三个关键变化,正好对上前面说的三个病因:
次数钉死在 3,于是2n2^n2n那个指数放大器被掐住了。一段三次曲线最多两个拐点,翻不起浪来。
提高精度靠加段而不是升次,于是"想更准"和"会更不稳"解耦了。
刚性从全局变成局部,于是动一个点只影响邻近两段。两端的约束不足,影响范围也被限制在最边上那一段。
高次多项式 三次样条 一条 20 次曲线 7 段三次曲线 ╮ ╭ ╭──╮ ╭──╮ ╭──╮ ╭── │ 一动全动,两端失控 │ │ │ │ │ │ │ │ ╰──────────────────────╯ ╰──╯──╰──╯──╰──╯──╰── ↑ ↑ ↑ 接缝处约定连续性代价是你从此得管接缝——得决定每个接缝做到 C¹ 还是 C²。但这笔交易很划算:把一个全局的、指数爆炸的问题,换成了一堆局部的、可精确控制的接缝条件。
全局的坏问题,换成局部的好问题。这是数值方法里反复出现的套路。
一分钟验证
不用相信上面任何话,跑一遍就有答案:
importnumpyasnpdefrunge(x):return1.0/(1.0+25.0*x**2)xs=np.linspace(-1,1,20000)truth=runge(xs)fornin[11,21,41]:forname,nodesin[("等间距 ",np.linspace(-1,1,n)),("切比雪夫",np.cos(np.arange(n)*np.pi/(n-1))),]:p=np.polyval(np.polyfit(nodes,runge(nodes),n-1),xs)print(f"{n:>3}点{name}最大误差{np.abs(p-truth).max():>14.4f}")重点看两件事:
等间距那几行,误差随点数一路膨胀。
切比雪夫那几行,次数完全相同,误差却一路下降。
同样的函数,同样的次数,只换了点的位置。这一组数字就是整篇文章的全部证据。
带走
不是次数太高,是点摆错了位置。
多项式全局刚性,两端约束不足,而等间距采样偏偏在两端给得最少——三件事叠起来,误差按2n2^n2n放大。
能控制采样点,就往两端加密。不能控制,就别用高次多项式,改用分段三次样条。
想要更精确,不是升次,是分段。