一、概述:Python数值计算生态
Python作为数据科学和科学计算领域的主流语言,提供了丰富而强大的数值计算工具链。从内置的数值类型到标准库中的专业模块,Python构建了一套完整的高精度计算生态。本文系统性地讲解Python标准库中与数值计算密切相关的六大核心模块:math、decimal、fractions、cmath、random和statistics,帮助读者深入理解并灵活运用这些工具解决实际问题。
Python的数值计算能力覆盖了从简单的四则运算到复杂的高精度十进制运算、从实数函数到复数域扩展、从基本随机数生成到高级统计推断的全方位需求。理解这些模块的设计哲学和适用场景,能够帮助开发者在不同精度要求和性能约束下做出最佳选择。
"计算机科学中的一切问题都可以通过增加一个间接层来解决。" —— David Wheeler。而在数值计算中,decima模块正是那个帮助我们规避浮点数陷阱的"间接层"。
适用场景一览:
- 金融计算 → decimal(避免分币误差)
- 科学计算 → math + cmath
- 游戏/模拟 → random
- 数据分析 → statistics
- 精确分数 → fractions
常见误区:
- 用float做金融计算(精度灾难)
- 不知decimal上下文对象的存在
- 在性能敏感处滥用decimal
- 忽略random模块的种子可控性
二、math模块详解:数学函数全解析
math模块是Python标准库中最基础的数学函数库,封装了C语言标准库的数学函数,性能优异。它包含三大类函数:数论与表示函数、幂指对函数、三角函数与角度转换、以及特殊函数。
2.1 数论与表示函数
math模块提供了一系列处理整数和浮点数表示的函数,其中ceil、floor、trunc、factorial、gcd、lcm等是日常开发中最常用的工具。
# 数论函数示例
import math
# 向上取整和向下取整
print(math.ceil(3.14)) # 4
print(math.floor(3.14)) # 3
print(math.trunc(3.14)) # 3(截断,等同于int())
# 阶乘与组合数
print(math.factorial(5)) # 120
print(math.comb(10, 3)) # 120(C(10,3)组合数)
print(math.perm(10, 3)) # 720(P(10,3)排列数)
# 最大公约数与最小公倍数(Python 3.9+)
print(math.gcd(48, 180)) # 12
print(math.lcm(12, 18)) # 36
# 浮点数分解
print(math.frexp(12.5)) # (0.78125, 4) => 12.5 = 0.78125 * 2^4
print(math.ldexp(0.78125, 4)) # 12.5(逆操作)
print(math.modf(3.14159)) # (0.14159, 3.0)(小数部分和整数部分)
2.2 幂指对函数
幂运算、指数函数和对数函数是科学计算中频繁使用的基础操作。math模块提供了exp、log、log2、log10、pow和sqrt等函数,支持自然底数和任意底数的对数计算。
# 幂指对函数
import math
# 指数函数
print(math.exp(1)) # 2.718281828459045(e^1)
print(math.expm1(1e-10)) # 1.00000000005e-10(高精度e^x-1,x很小时避免精度损失)
# 对数函数
print(math.log(100)) # 4.605170185988092(自然对数)
print(math.log(100, 10)) # 2.0(以10为底)
print(math.log2(1024)) # 10.0
print(math.log10(1000)) # 3.0
print(math.log1p(1e-10)) # 9.9999999995e-11(高精度log(1+x),x很小时避免精度损失)
# 幂运算与开方
print(math.pow(2, 10)) # 1024.0
print(math.sqrt(2)) # 1.4142135623730951
print(math.isclose(0.1 + 0.2, 0.3)) # True(浮点数容差比较,非常重要!)
print(math.isclose(1e-100, 0)) # False(默认相对容差rel_tol=1e-09)
2.3 三角函数与双曲函数
math模块支持完整的三角函数(sin、cos、tan)及其反函数(asin、acos、atan、atan2),以及双曲函数(sinh、cosh、tanh)系列。所有角度均使用弧度制,配合degrees和radians函数实现角度与弧度的互转。
# 三角函数示例
import math
# 角度与弧度转换
degrees = 45
rad = math.radians(degrees) # 角度转弧度
print(rad) # 0.7853981633974483
print(math.degrees(rad)) # 45.0(弧度转角度)
# 基本三角函数
print(math.sin(math.pi / 6)) # 0.49999999999999994 (sin 30度)
print(math.cos(math.pi / 3)) # 0.5000000000000001 (cos 60度)
print(math.tan(math.pi / 4)) # 0.9999999999999999 (tan 45度)
# 反三角函数
print(math.asin(0.5)) # 0.5235987755982989(约30度)
print(math.acos(0.5)) # 1.0471975511965979(约60度)
print(math.atan(1)) # 0.7853981633974483(约45度)
print(math.atan2(1, 1)) # 0.7853981633974483(atan(y/x),处理象限)
# 双曲函数
print(math.sinh(1)) # 1.1752011936438014
print(math.cosh(1)) # 1.5430806348152437
print(math.tanh(1)) # 0.7615941559557649
# 距离计算(勾股定理)
print(math.hypot(3, 4)) # 5.0(sqrt(3^2 + 4^2))
2.4 特殊函数与常量
math模块提供了gamma函数(阶乘的实数域推广)、误差函数erf/erfc,以及多个重要数学常量。这些在概率统计和工程计算中有着广泛应用。
# 特殊函数与常量
import math
# 数学常量
print(math.pi) # 3.141592653589793
print(math.e) # 2.718281828459045
print(math.tau) # 6.283185307179586(2*pi)
print(math.inf) # inf(正无穷)
print(math.nan) # nan(非数字)
# Gamma函数(阶乘的扩展)
print(math.gamma(5)) # 24.0(等于4!)
print(math.lgamma(5)) # 3.1780538303479458(ln(gamma(5)))
# 误差函数(概率统计中常用)
print(math.erf(0)) # 0.0
print(math.erf(1)) # 0.8427007929497149
print(math.erfc(1)) # 0.1572992070502851(1 - erf(x))
性能提示:math模块的函数是对底层C库的封装,性能出色。但请注意,每次调用Python函数都有解释器开销。在大量循环中调用math函数时,考虑将函数引用赋值给局部变量以提升性能:sin = math.sin; cos = math.cos。
三、decimal模块:高精度十进制运算
decimal模块是Python解决浮点数精度问题的核心工具。与binary float不同,decimal采用十进制浮点表示,能够精确表达所有十进制有限小数,特别适用于金融计算和需要精确舍入控制的场景。
3.1 浮点数的精度陷阱
在深入decimal之前,我们必须先理解为什么float会"不精确"。计算机使用二进制表示小数,而大部分十进制小数无法被二进制有限表示。
# 经典的浮点数陷阱
print(0.1 + 0.2) # 0.30000000000000004(不是0.3!)
print(0.1 + 0.2 == 0.3) # False
print(0.3 - 0.1) # 0.19999999999999998(不是0.2!)
# 累积误差示例
total = 0.0
for _ in range(1000000):
total += 0.1
print(total) # 100000.0000013328(理论值是100000)
print(total - 100000) # 0.0000013328(累积误差!)
# 更大的误差
print(1.0 / 3.0) # 0.3333333333333333(精度损失)
print(1.0 / 3.0 * 3) # 1.0(恰好恢复——巧合!)
3.2 Decimal的创建与上下文
decimal模块的核心是Decimal类,其关键设计在于通过上下文对象(Context)统一控制精度、舍入模式和异常处理。使用getcontext()获取当前线程的上下文,通过setcontext()进行全局配置。
# Decimal基本使用
from decimal import Decimal, getcontext, setcontext, Context, ROUND_HALF_UP
# 正确创建方式:从字符串或整数构造
d1 = Decimal('0.1') # ✅ 推荐:字符串构造
d2 = Decimal(1) / Decimal(3) # ✅ 精确分数
d3 = Decimal(10) ** -5 # ✅ 整数运算
# 避免从float构造
bad = Decimal(0.1) # ❌ 不推荐:传入float会先把0.1变成不精确的二进制
print(bad) # 0.1000000000000000055511151231257827021181583404541015625
# 基本运算
print(Decimal('0.1') + Decimal('0.2')) # 0.3(正确!)
print(Decimal('1.0') / Decimal('3.0')) # 0.3333333333333333333333333333(28位精度,默认上下文)
3.3 精度与舍入模式控制
decimal模块最强大的特性在于精确控制计算精度和舍入模式。通过调整上下文对象,开发者可以针对不同场景灵活配置。金融计算通常要求"四舍五入"模式,而科学计算可能更倾向于"最近偶数"模式以减小统计偏差。
# 上下文控制
from decimal import Decimal, getcontext, setcontext, Context, ROUND_HALF_UP, ROUND_HALF_EVEN, ROUND_FLOOR, ROUND_CEILING
# 查看当前上下文
ctx = getcontext()
print(ctx) # Context(prec=28, rounding=ROUND_HALF_EVEN, ...)
# 修改全局精度
getcontext().prec = 50 # 设置为50位有效数字
d = Decimal(1) / Decimal(3)
print(d) # 0.33333333333333333333333333333333333333333333333333(50位)
# 舍入模式
ctx = getcontext()
ctx.rounding = ROUND_HALF_UP # 改为四舍五入(金融标准)
# 使用局部上下文(推荐方式)
with localcontext() as ctx:
ctx.prec = 6
ctx.rounding = ROUND_HALF_UP
result = Decimal('1') / Decimal('7')
print(result) # 0.142857(局部6位精度)
# 不同舍入模式对比
val = Decimal('2.675')
print(val.quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN)) # 2.68(银行家舍入)
print(val.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)) # 2.68
print(val.quantize(Decimal('0.01'), rounding=ROUND_FLOOR)) # 2.67
print(val.quantize(Decimal('0.01'), rounding=ROUND_CEILING)) # 2.68
3.4 金融计算实战案例
decimal模块在金融领域的应用最为典型。利息计算、税率计算、汇率换算等场景对精度有着严苛要求,即使单笔误差只有一分钱,在大量交易中也会造成巨大差错。
# 金融计算实战:分期付款计算
from decimal import Decimal, getcontext, ROUND_HALF_UP
from decimal import localcontext
def calc_installment(principal, annual_rate, months):
"""等额本息月供计算"""
getcontext().rounding = ROUND_HALF_UP
p = Decimal(str(principal))
r = Decimal(str(annual_rate)) / Decimal('100') / Decimal('12')
n = Decimal(str(months))
# 月供 = P * r * (1+r)^n / ((1+r)^n - 1)
compound = (Decimal(1) + r) ** n
payment = p * r * compound / (compound - Decimal(1))
return payment.quantize(Decimal('0.01'))
# 贷款100万,年利率4.5%,30年(360个月)
monthly = calc_installment(1000000, 4.5, 360)
print(f"月供: {monthly}元") # 精确结果,无浮点误差
# 累计还款
total_payment = monthly * 360
print(f"总还款额: {total_payment}元")
print(f"总利息: {total_payment - Decimal('1000000')}元")
3.5 Decimal的注意事项
重要提醒:
- 从字符串构造:始终使用字符串或整数构造Decimal,避免float构造带来的精度损失。
- 性能开销:Decimal运算比float慢数十倍,不要在不需高精度的场景中使用。
- 上下文隔离:getcontext()返回的是当前线程的上下文,修改会影响该线程中所有Decimal运算。
- 量化操作:在获取最终结果时,务必使用quantize()方法按需确定精度。
- 整除注意:/ 返回Decimal除法结果,// 对Decimal返回截断除法。
四、fractions模块:精确分数运算
fractions模块提供了基于有理数的精确算术。Fraction类将数值表示为分子/分母的形式,在有理数范围内保证计算绝对精确,没有任何精度损失。这在需要精确比较和代数运算的场景中非常有用。
# fractions模块详解
from fractions import Fraction
from decimal import Decimal
import math
# 创建Fraction的多种方式
f1 = Fraction(1, 3) # 1/3(整数构造)
f2 = Fraction('3/7') # 3/7(字符串构造)
f3 = Fraction(0.75) # 3/4(从float构造,自动化简)
f4 = Fraction(Decimal('0.125')) # 1/8(从Decimal构造)
print(f1) # 1/3
print(f2) # 3/7
print(f3) # 3/4
print(f4) # 1/8
# 自动约分
f = Fraction(42, 56)
print(f) # 3/4(自动约分到最简形式)
# 精确算术运算
a = Fraction(1, 3)
b = Fraction(1, 6)
print(a + b) # 1/2(精确!)
print(a - b) # 1/6
print(a * b) # 1/18
print(a / b) # 2(精确!)
# 与float混合运算
result = Fraction(1, 3) + 0.1
print(result) # 0.43333333333333335(转为float后运算,失去精确性)
# 保持精确比较
print(Fraction(1, 10) + Fraction(2, 10) == Fraction(3, 10)) # True(float做不到!)
# 使用Fraction避免精度问题
def estimate_pi(n):
"""使用莱布尼茨级数近似π(Fraction版本,精确)"""
pi_approx = Fraction(0, 1)
for k in range(n):
pi_approx += Fraction((-1) ** k, 2 * k + 1)
return 4 * pi_approx
print(float(estimate_pi(100000))) # 3.1415826535897198(有理数精确累加)
五、cmath模块:复数数学函数
cmath模块是math模块的复数版本,提供了适用于复数域的数学函数。它包含了复数的创建、运算、转换以及各种复变函数,是信号处理、电路分析和量子计算等领域的必备工具。
# cmath模块:复数数学
import cmath
import math
# 复数创建
z1 = 3 + 4j # 直接创建
z2 = complex(3, 4) # 通过complex函数
print(z1, z2) # (3+4j) (3+4j)
# 复数的基本属性
print(z1.real) # 3.0(实部)
print(z1.imag) # 4.0(虚部)
print(z1.conjugate()) # (3-4j)(共轭复数)
# 模和辐角
z = 3 + 4j
print(abs(z)) # 5.0(模)
print(cmath.phase(z)) # 0.9272952180016122(辐角,弧度)
print(cmath.polar(z)) # (5.0, 0.9272952180016122)(极坐标形式)
print(cmath.rect(5, 0.9272952180016122)) # (3+4j)(极坐标转直角坐标)
# 复变函数
print(cmath.exp(1j * cmath.pi)) # (-1+1.2246467991473532e-16j)(欧拉公式e^(iπ) = -1)
print(cmath.sqrt(-1)) # 1j
print(cmath.log(-1)) # 3.141592653589793j(ln(-1) = iπ)
print(cmath.sin(1j)) # 1.1752011936438014j(sin(i) = i*sinh(1))
# 解二次方程 ax^2 + bx + c = 0
def quadratic(a, b, c):
disc = cmath.sqrt(b**2 - 4*a*c)
x1 = (-b + disc) / (2*a)
x2 = (-b - disc) / (2*a)
return x1, x2
# x^2 + x + 1 = 0(判别式小于0)
x1, x2 = quadratic(1, 1, 1)
print(x1) # (-0.5+0.8660254037844386j)
print(x2) # (-0.5-0.8660254037844386j)
print(x1**2 + x1 + 1) # 验证:约等于0
六、random模块进阶用法
random模块提供了丰富的伪随机数生成工具。除了基础函数外,其进阶功能包括带权重的随机选择、不重复采样、序列打乱以及可重现随机序列的种子控制,在游戏开发、模拟测试和蒙特卡洛方法中有广泛应用。
6.1 进阶选择和采样
# random模块进阶用法
import random
# 设置种子(保证可重现)
random.seed(42)
print(random.random()) # 0.6394267984578837(种子固定,结果可复现)
# 带权重的随机选择
colors = ['红', '绿', '蓝']
weights = [0.5, 0.3, 0.2] # 权重
print(random.choices(colors, weights=weights, k=10))
# 示例:['红', '绿', '红', '蓝', '红', '红', '蓝', '绿', '红', '红']
# 累积权重(更高效)
print(random.choices(colors, cum_weights=[0.5, 0.8, 1.0], k=5))
# 不重复采样(无放回)
cards = [f'{rank}{suit}' for rank in 'A23456789JQK' for suit in '♠♥♣♦']
hand = random.sample(cards, k=5) # 从扑克牌中随机抽5张(不重复)
print(hand)
# 序列打乱(原地操作)
deck = cards.copy()
random.shuffle(deck)
print(deck[:5]) # 打乱后的前5张
6.2 常见随机分布
# 各种概率分布
import random
import math
# 均匀分布
print(random.uniform(10, 20)) # [10, 20]范围的均匀分布随机数
# 正态分布(高斯分布)
samples = [random.gauss(0, 1) for _ in range(5)] # 均值0,标准差1
print(samples)
# 三角分布
print(random.triangular(0, 10, 5)) # 最小值0,最大值10,众数5
# 指数分布(模拟事件间隔)
print(random.expovariate(1.0)) # 参数λ=1的指数分布
# Beta分布(贝叶斯统计中常用作先验)
print(random.betavariate(2, 5))
# 蒙特卡洛模拟:估算π值
def monte_carlo_pi(n):
inside = 0
for _ in range(n):
x = random.uniform(-1, 1)
y = random.uniform(-1, 1)
if x*x + y*y <= 1:
inside += 1
return 4 * inside / n
# 模拟越多,结果越精确
print(monte_carlo_pi(10000)) # 约3.14
print(monte_carlo_pi(100000)) # 约3.141
print(monte_carlo_pi(1000000)) # 约3.1415
七、statistics模块:统计函数
statistics模块是Python 3.4引入的标准统计库,提供了基本的描述性统计函数。它支持int、float、Decimal和Fraction类型的输入,自动选择合适精度进行计算,是轻量级统计分析的便捷选择。
# statistics模块详解
import statistics as stats
from fractions import Fraction
from decimal import Decimal
data = [1.5, 2.3, 3.7, 4.1, 5.0, 5.0, 6.2, 7.8, 8.0, 9.5]
# 集中趋势度量
print(stats.mean(data)) # 5.31(算术平均)
print(stats.median(data)) # 5.0(中位数——不受异常值影响)
print(stats.mode([1,1,2,3,3,3])) # 3(众数)
print(stats.median_low(data)) # 5.0(低中位数)
print(stats.median_high(data)) # 5.0(高中位数)
print(stats.median_grouped(data)) # 5.0(分组中位数)
# 离中趋势度量
print(stats.pvariance(data)) # 6.0769(总体方差)
print(stats.variance(data)) # 6.7521(样本方差——分母n-1)
print(stats.pstdev(data)) # 2.4651(总体标准差)
print(stats.stdev(data)) # 2.5985(样本标准差)
# 多类型支持
mixed_data = [Fraction(1, 3), Fraction(1, 6), Fraction(1, 2)]
print(stats.mean(mixed_data)) # 1/3(自动返回Fraction)
decimal_data = [Decimal('1.5'), Decimal('2.5'), Decimal('3.5')]
print(stats.mean(decimal_data)) # 2.5(自动返回Decimal,保持精度)
八、浮点数精度问题深入分析
浮点数精度问题是每个Python开发者都必须理解的底层知识。IEEE 754标准的双精度浮点数使用52位有效数字(约15-17位十进制有效数字),这种有限精度在科学计算、金融工程和数值分析中会产生各种"反直觉"的现象。
8.1 浮点误差的根源
二进制浮点数无法精确表示所有十进制小数,就像十进制无法精确表示1/3一样。0.1在二进制中是无限循环小数:0.000110011001100110011...,这导致任何有限精度的二进制表示都存在舍入误差。
# 深入理解浮点误差
import math
# 0.1的二进制表示不能精确终止
print(f"{0.1:.30f}") # 0.100000000000000005551115123126
print(f"{0.2:.30f}") # 0.200000000000000011102230246252
print(f"{0.3:.30f}") # 0.299999999999999988897769753748
# 浮点数比较陷阱
print(0.1 + 0.2 == 0.3) # False
print(abs((0.1 + 0.2) - 0.3) < 1e-10) # True(手动容差比较)
# 使用math.isclose(推荐)
print(math.isclose(0.1 + 0.2, 0.3)) # True(默认相对容差)
print(math.isclose(1e-100, 0)) # False(相对容差默认1e-9)
print(math.isclose(1e-100, 0, abs_tol=1e-100)) # True(指定绝对容差)
# 大数吃小数
large = 1e16
small = 1.0
print(large + small == large) # True(1被吃掉!因为精度不够)
print(large + small - large) # 0.0(丢失了!)
8.2 避免浮点误差的最佳实践
# 浮点数最佳实践总结
# 1. 使用Decimal进行精确计算
from decimal import Decimal, ROUND_HALF_UP
price = Decimal('19.99')
tax_rate = Decimal('0.06')
total = (price * (1 + tax_rate)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
print(total) # 21.19(精确的货币计算)
# 2. 使用Fraction处理有理数
from fractions import Fraction
pie_shares = Fraction(1, 8) # 每人1/8
print(pie_shares * 3) # 3/8(精确的有理数运算)
# 3. 使用math.isclose比较浮点数
import math
a, b = 0.0, 0.0
for i in range(100):
a += 0.1
b = round(b + 0.1, 10) # 手动舍入控制
print(f"a = {a:.20f}, b = {b:.20f}")
# 4. 使用round控制有效位数
x = 3.141592653589793
print(round(x, 4)) # 3.1416
# 5. 避免减法抵消
import math
# 不好的方式:相近大数相减
x = 1e15
y = 1e15 + 1
bad = y - x # 1.0 ✅(这里没问题,但大数时可能出问题)
# 真正的减法抵消示例
a = 1.000000000000001
b = 1.0
print(a - b) # 8.881784197001252e-16(精度损失严重!理论值是1e-15)
九、综合实战案例
我们将通过一个完整的实战案例——科学计算器工具,综合运用本章讲解的多个模块。这个案例展示了如何在同一个应用中根据不同的计算需求选择合适的数值计算工具。
# 综合实战:多功能科学计算工具
import math
import cmath
import decimal
from decimal import Decimal, ROUND_HALF_UP
import random
import statistics
class AdvancedCalculator:
"""多功能科学计算器:演示各数值计算模块的综合运用"""
@staticmethod
def trig_precise(angle_deg):
"""高精度三角函数计算"""
rad = math.radians(angle_deg)
return {
'sin': math.sin(rad),
'cos': math.cos(rad),
'tan': math.tan(rad),
'sinh': math.sinh(rad),
'cosh': math.cosh(rad)
}
@staticmethod
def financial_calc(principal, rate, years):
"""金融计算:复利终值"""
p = Decimal(str(principal))
r = Decimal(str(rate))
n = Decimal(str(years))
# 复利终值 = P * (1 + r)^n
future = p * (Decimal(1) + r) ** n
return future.quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)
@staticmethod
def complex_analysis(z_real, z_imag):
"""复数分析"""
z = complex(z_real, z_imag)
return {
'modulus': abs(z),
'phase': cmath.phase(z),
'conjugate': z.conjugate(),
'sqrt': cmath.sqrt(z),
'exp': cmath.exp(z),
'log': cmath.log(z)
}
@staticmethod
def monte_carlo_integration(func, a, b, n=100000):
"""蒙特卡洛积分估算"""
total = 0.0
for _ in range(n):
x = random.uniform(a, b)
total += func(x)
return (b - a) * total / n
@staticmethod
def statistical_analysis(data):
"""统计分析"""
return {
'mean': statistics.mean(data),
'median': statistics.median(data),
'stdev': statistics.stdev(data) if len(data) > 1 else 0,
'min': min(data),
'max': max(data)
}
# 使用示例
calc = AdvancedCalculator()
# 1. 三角函数
print("sin(30°) =", calc.trig_precise(30)['sin'])
# 2. 金融计算
print("复利终值:", calc.financial_calc(10000, 0.05, 10))
# 3. 复数分析
print("复数分析:", calc.complex_analysis(3, 4))
# 4. 蒙特卡洛积分:计算∫₀¹ x² dx = 1/3
result = calc.monte_carlo_integration(lambda x: x**2, 0, 1)
print(f"蒙特卡洛积分: {result:.6f} (理论值: 0.333333)")
# 5. 统计分析
sample = [random.gauss(0, 1) for _ in range(1000)]
stats_result = calc.statistical_analysis(sample)
print(f"均值: {stats_result['mean']:.4f}, 标准差: {stats_result['stdev']:.4f}")
十、总结与最佳实践
Python的数值计算模块各有所长,理解它们的设计哲学和适用场景对于写出健壮、高效的代码至关重要。以下是核心要点总结:
核心总结:
- math模块:基础数学函数,性能优先,精度由IEEE 754 double决定。适用于科学计算、工程计算等对性能要求高、对微小误差不敏感的场景。
- decimal模块:高精度十进制计算,精度可控、舍入模式可配置。金融计算、货币运算、税务计算的唯一正确选择。
- fractions模块:有理数精确算术,完全无精度损失。适用于代数运算、精确比较、数学教育等场景。
- cmath模块:复数域的数学函数扩展,与math接口高度一致。信号处理、电路分析、量子力学模拟的必备工具。
- random模块:伪随机数生成,支持分布、权重和种子控制。模拟测试、游戏开发、蒙特卡洛方法的核心依赖。
- statistics模块:轻量级描述统计,支持多种数值类型。快速数据探索、简单统计分析的便捷选择。
选择指南:
- 只需要一个近似结果? → 使用float + math模块,简单高效。
- 在算钱? → 必须使用decimal,选择ROUND_HALF_UP舍入模式。
- 需要精确的有理数运算? → 使用fractions.Fraction。
- 处理负数开方或复变函数? → 使用cmath替代math。
- 需要可复现的随机实验? → 显式调用random.seed()设置种子。
- 快速统计分析、不需要pandas? → 使用statistics模块。
常见的坑:
- 永远不要用float == float做相等比较——改用math.isclose()。
- 永远不要用Decimal(float_value)构造——用字符串"0.1"而非0.1。
- 多层循环/大规模数值运算中慎用Decimal——性能开销显著。
- random模块默认使用系统时间初始化种子——需要确定性时显式seed()。
- Fraction与float混合运算会失去精确性——全程保持Fraction类型。