Round-off error
Round-off error 的原因是数值计算的过程中, 机器的精度是有限的. wikipedia: Round-off error
Unstable method
计算 Goledn Mean
\begin{align} \phi = \frac{\sqrt{5} - 1}{2} \approx 0.61803398 \end{align}的 \(n\) 次幂 \(\phi^n\) . 可以证明它满足递推关系
\begin{align} \phi^{n + 1} = \phi^{n - 1} - \phi^n \end{align}使用此递推关系, 可以由原来的乘法变成减法, 会节约计算资源. 但是此递推关系还有另一 个解
\begin{align} - \frac{1}{2}(\sqrt{5} + 1) \end{align}因为它的绝对值是大于 \(1\) 的. 所以混入任何 round-off error 都会指数发散. 因此这个 递推算法是一个 unstable method.
import numpy as np |
解决方法
解决方法之一是使用更高精度的数值类型. 虽然此法在效率上的代价是巨大的. Mathematica 中设置 WorkingPrecision 即为此方法.
在 python, mpmath
包提供了类似的处理方法
import numpy as np |
unstable_method_with_mpmath.py
可以看出, 将求根的计算精度由 numpy.float64
(53个二进制位表示一个浮点数) 提高到
70 个二进制位表示一个浮点数, 在 \(n\le 80\) 的范围内, round-off error 被压住了.
另一种出现 round-off error 的情况
从解析上可以得到, 被积函数在 \(k\to \infty\) 时的行为是 \(\sim 1/k^2\) . 根号中的第一项和第二 项 \(-3k^2\) 在 \(k\to \infty\) 时各自是发散的, 但是相加之后是收敛的.
但是数值计算上, 当 \(k\) 很大时, 在保留的有效数字个数有限的情况下, 相加得到的结果 可能在有效数字之外了, 因此相加的结果是 round-off error. 反映在结果上就是本来应该 \(\sim 1/k^2\to 0\) 的, 却出现抖动.
这时也可以用 mpmath 提高精度.
import numpy as np |
可以看出如果用 numpy.float64
计算会提示 round-off error.
Reference
- wikipedia: Round-off error
- Winkler, J. R. Numerical recipes in C: The art of scientific computing, second edition. Endeavour 17, 201 (1993). Chap 1.3
- wikipedia: Numerical stability
- wikipedia: Double-precision floating-point format
- mpmath's documentation
- https://scicomp.stackexchange.com/questions/21483/how-to-avoid-the-round-off-errors-in-the-larger-calculations
- Fan Yang 的讨论