Python 数学计算库全景

IEEE 754 浮点数标准

IEEE 754(英文全称:IEEE Standard for Floating-Point Arithmetic,中文:浮点数算术标准)由 IEEE(电气电子工程师学会)于 1985 年首次发布,是目前全球最广泛使用的浮点数计算标准。2008 年发布修订版(IEEE 754-2008,新增十进制浮点格式),2019 年再次更新(IEEE 754-2019)。

官方地址:https://standards.ieee.org/standard/754-2019.html

制定者:加州大学伯克利分校的 William Kahan 教授主导设计,他因此获得 1989 年图灵奖,被称为「浮点数之父」。

几乎所有现代计算机(包括 CPU、GPU)的浮点运算都遵循此标准。它定义了浮点数在内存中的二进制存储格式,是所有科学计算的底层基础。

核心原理

一个浮点数被拆分为三部分:

(-1)^符号位 × 1.尾数 × 2^(指数 - 偏移量)
类型 总位数 符号位 指数位 尾数位 有效精度(十进制)
float16(半精度) 16 1 5 10 ~3 位
float32(单精度) 32 1 8 23 ~7 位
float64(双精度) 64 1 11 52 ~15 位

精度损失的根源

IEEE 754 用二进制表示小数,但很多十进制小数在二进制下是无限循环的:

0.1(十进制)= 0.00011001100110011...(二进制,无限循环)
0.2(十进制)= 0.00110011001100110...(二进制,无限循环)

就像十进制无法精确写出 1/3 = 0.3333...一样,二进制也无法精确表示 0.1。浮点数只能截断到有限位,产生微小误差。

经典案例:0.1 + 0.2 ≠ 0.3

>>> 0.1 + 0.2
0.30000000000000004

>>> 0.1 + 0.2 == 0.3
False

原因链:0.1 和 0.2 各自存储时就有微小截断误差 → 两个近似值相加 → 误差叠加 → 结果不再是精确的 0.3。这不是 Python 的 bug,而是所有使用 IEEE 754 的语言(C/C++/Java/JS/Go……)的共同行为。

与科学计算的关系

IEEE 754 是科学计算的双刃剑:

因此,理解 IEEE 754 是理解科学计算精度问题的起点。下文的各个 Python 数学库,本质上都是在 IEEE 754 的不同局限上提供补救方案。


标准库(无需安装)

math — 基础数学函数

Python 内置的浮点数学工具箱,底层是 C 的 double(float64),精度约 15~17 位有效数字。

import math

math.pi          # 3.141592653589793
math.e           # 2.718281828459045
math.sqrt(2)     # 1.4142135623730951
math.log(10)     # 2.302585092994046(自然对数)
math.sin(math.pi / 2)  # 1.0
math.factorial(10)     # 3628800
math.gcd(12, 8)        # 4

适用场景:日常数学运算、几何计算、三角函数。 局限:受限于 IEEE 754 双精度,无法做任意精度计算。

cmath — 复数数学

math 的复数版本,支持复数的三角函数、对数、开方等。

import cmath

cmath.sqrt(-1)       # 1j
cmath.exp(1j * cmath.pi)  # (-1+1.2246467991473532e-16j)  即欧拉公式 e^(iπ) = -1

decimal — 精确十进制运算

专为金融/会计场景设计,解决浮点数无法精确表示十进制小数的问题。

from decimal import Decimal, getcontext

# 经典问题:0.1 + 0.2 ≠ 0.3
0.1 + 0.2                          # 0.30000000000000004(IEEE 754 浮点误差)
Decimal('0.1') + Decimal('0.2')    # Decimal('0.3')(精确)

# 用 mpmath 验证误差来源
from mpmath import mp
mp.dps = 20
mp.mpf('0.1')   # 0.1 在精确算术中的真值
# 而 float(0.1) 实际存储的是 0.1000000000000000055511151231257827021181583404541015625

为什么 0.1 + 0.2 会出错? 因为 0.1 在二进制下是无限循环小数(0.0001100110011...),IEEE 754 只能截断存储,0.2 同理。两个近似值相加,误差叠加,结果不再是精确的 0.3。decimal 通过十进制内部表示绕过了二进制截断问题。

# 控制运算精度
getcontext().prec = 50
Decimal(1) / Decimal(7)  # 50 位有效数字

关键特性: - prec 控制的是有效数字总位数(含整数部分),不是小数位数 - 从字符串创建 Decimal('3.14') 精确存储;从浮点数创建 Decimal(3.14) 会带入浮点误差 - 支持自定义舍入模式(ROUND_HALF_UP 等),适合货币计算

适用场景:金额计算、需要精确十进制表示的场景。

fractions — 分数运算

用分子/分母精确表示有理数,避免浮点近似。

from fractions import Fraction

Fraction(1, 3) + Fraction(1, 6)   # Fraction(1, 2)
Fraction('0.1') + Fraction('0.2') # Fraction(3, 10)
float(Fraction(22, 7))            # 3.142857142857143

适用场景:需要精确有理数运算、教学演示。

statistics — 统计分析

内置的基础统计函数。

import statistics

data = [2.75, 1.75, 1.25, 0.75, 0.5, 1.25, 3.5]
statistics.mean(data)     # 1.6785714285714286
statistics.median(data)   # 1.25
statistics.stdev(data)    # 1.035749322937853
statistics.variance(data) # 1.0727777777777778

random — 随机数

import random

random.random()        # [0.0, 1.0) 均匀分布
random.randint(1, 100) # [1, 100] 随机整数
random.gauss(0, 1)     # 正态分布
random.choice([1, 2, 3])  # 随机选择

第三方库

mpmath — 任意精度数学

高精度数值计算的瑞士军刀,可计算数学常数和函数到任意精度。

from mpmath import mp

mp.dps = 100  # 小数点后 100 位(decimal places)
mp.pi         # π 的 100 位精确值
mp.e          # e 的 100 位精确值
mp.sqrt(2)    # √2 的 100 位精确值
mp.sin(mp.pi / 4)  # sin(π/4) 高精度结果

关键特性: - dps(decimal places)控制小数点后的位数,语义比 decimal.prec 更直观 - 内置几十个数学常数(π、e、γ、φ……)和数百个数学函数 - SymPy 的底层数值引擎就是 mpmath - 算法实时计算,非硬编码

适用场景:数学研究、验证浮点精度损失、计算常数到任意位数。

numpy — 数值计算基石

Python 科学计算生态的核心,提供高性能多维数组和向量化运算。

import numpy as np

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])
np.dot(a, b)       # 32
np.mean(a)         # 2.0
np.linspace(0, 1, 5)  # [0.  0.25 0.5  0.75 1.  ]
np.random.randn(3, 3) # 3×3 标准正态随机矩阵

关键特性: - 底层 C/Fortran 实现,比纯 Python 循环快 100 倍以上 - 支持 float16/float32/float64/float128 等多种精度 - 广播机制(Broadcasting)简化多维运算 - 模型量化的核心工具:权重的截取、缩放、类型转换都通过 numpy 完成

适用场景:矩阵运算、信号处理、图像操作、机器学习数据预处理。

scipy — 科学计算全家桶

基于 numpy 构建,提供更高级的科学计算算法。

from scipy import optimize, integrate, signal

# 求方程根
optimize.fsolve(lambda x: x**3 - 2*x - 5, 2)  # [2.09455148]

# 数值积分
integrate.quad(lambda x: x**2, 0, 1)  # (0.33333333333333337, 3.7e-15)

# 信号滤波
signal.butter(4, 0.2)  # 4 阶 Butterworth 滤波器

子模块覆盖:优化、积分、插值、统计、线性代数、信号处理、图像处理、稀疏矩阵等。

sympy — 符号数学

做代数推导而非数值计算,能输出精确的数学表达式。

from sympy import symbols, diff, integrate, solve, pi

x = symbols('x')
diff(x**3, x)            # 3*x**2(求导)
integrate(x**2, x)       # x**3/3(不定积分)
solve(x**2 - 2, x)       # [-√2, √2](精确解,非近似值)
pi.evalf(100)            # π 的 100 位(底层调用 mpmath)

适用场景:公式推导、方程求解、教学演示、LaTeX 输出。

gmpy2 — 底层高精度整数/浮点

C 库 GMP 的 Python 绑定,速度远超纯 Python 实现。

import gmpy2

gmpy2.mpfr('3.14', 200)   # 200 位精度的浮点数
gmpy2.fac(100)            # 100! 的精确值(158 位整数)

适用场景:需要极致性能的高精度计算(如密码学、大数分解)。


选型速查

需求 推荐库 安装
日常数学 math 自带
金额/财务 decimal 自带
精确分数 fractions 自带
基础统计 statistics 自带
看 π 到 1000 位 mpmath pip install mpmath
矩阵/数组/量化 numpy pip install numpy
优化/积分/信号 scipy pip install scipy
符号推导/公式 sympy pip install sympy
极速大数运算 gmpy2 pip install gmpy2

与模型量化的关系

模型量化本质上是在不同数值精度之间做权衡:

理解这些数学库的行为,有助于深入理解量化过程中的精度损失机制。

相关笔记