Skip to content

9.1 浮点精度

浮点数精度是数值计算的基石——忽略它会写出"看似正确实则错误"的代码。量化金融中涉及大量数值运算,理解浮点误差是写出可靠交易系统的前提。


机器 Epsilon

机器 epsilon (εm\varepsilon_m) 是计算机浮点数系统中,满足 1.0+ε1.01.0 + \varepsilon \neq 1.0 的最小正数。在 IEEE 754 标准中:

精度类型机器 epsilon有效位数
单精度float322231.19×1072^{-23} \approx 1.19 \times 10^{-7}~7 位
双精度float642522.22×10162^{-52} \approx 2.22 \times 10^{-16}~16 位

Python 中可用以下方式验证:

python
eps = 1.0
while 1.0 + eps != 1.0:
    eps /= 2.0
print(f"机器 epsilon = {eps * 2}")  # 输出: 2.220446049250313e-16

灾难性抵消(Catastrophic Cancellation)

当两个大小相近的数相减时,有效数字大量丢失——这是数值计算中最危险的误差来源之一。

手算实例:(1016+1)1016(10^{16} + 1) - 10^{16}

双精度浮点数只有约 16 位有效数字。101610^{16} 在双精度下表示为 1.0×10161.0 \times 10^{16}

步骤数学运算计算机实际发生了什么
11016+110^{16} + 1101610^{16} 的第 17 位是 1,但双精度只有 ~16 位,1 被截断
2结果计算机认为 1016+1=101610^{16} + 1 = 10^{16}
3(1016+1)1016(10^{16} + 1) - 10^{16}10161016=010^{16} - 10^{16} = 0
4理论正确结果11

验证:

python
print((10**16 + 1) - 10**16)  # 输出: 0.0

如何避免灾难性抵消?

1. 代数变换——共轭有理化

将减法转化为加法或乘法形式。例如,计算 1x+δx\frac{1}{\sqrt{x+\delta} - \sqrt{x}} 时,分母是两个接近的数相减(灾难性抵消),通过乘以共轭 x+δ+xx+δ+x\frac{\sqrt{x+\delta} + \sqrt{x}}{\sqrt{x+\delta} + \sqrt{x}} 来消除减法: \frac{1}{\sqrt{x + \delta} - \sqrt{x}} \quad\rightarrow\quad \frac{\sqrt{x + \delta} + \sqrt{x}}{\delta}

### 2. Kahan 求和算法 当需要累加大量浮点数时,使用 Kahan 补偿求和: ```python def kahan_sum(values): """Kahan 补偿求和,减少累积误差""" total = 0.0 compensation = 0.0 # 误差补偿项 for v in values: y = v - compensation t = total + y compensation = (t - total) - y total = t return total ``` ### 3. 使用高精度库 Python 的 `Decimal` 模块或 `math.fsum` 提供了更高精度的数值运算。 --- ## Quant Link:大规模优化中的浮点问题 在**计算期权净值**时,如果两个非常大的头寸方向相反(如一个看涨 + 执行价 100 的空头 + 一个执行价 101 的多头),它们的差值很小但包含关键定价信息——灾难性抵消会**完全抹去**这个价差信号。 ### 常见场景 | 场景 | 风险 | 解决方案 | |------|------|----------| | Greeks 有限差分 | $\epsilon$ 过小导致灾难性抵消 | 选择 $\epsilon \approx \sqrt{\varepsilon_m} \cdot S$ | | 大数相减求价差 | 有效位数丢失 | 代数变换;使用高精度库 | | 大规模组合归因 | 累积舍入误差 | Kahan 求和;Decimal | > **实践建议**:在量化系统中,尽量使用 `float64`(Python 默认);对精度要求极高的金额计算(如清算对账),使用 `Decimal` 或整数分单位;在数值 Greeks 计算中,遵循 $\epsilon \approx \sqrt{\varepsilon_m} \cdot S$ 的经验法则。 \n> **下一步**:继续学习 [9.2 根求解](./9.2-root-finding)

Built with VitePress