首页 > 移动开发 > HTML5 > 在Python中,如何解决浮点数精度问题?
在 Python 中解决浮点数精度问题,可通过以下 8 种方法实现不同场景下的精确计算需求:
from decimal import Decimal, getcontext# 设置精度和舍入模式(默认28位精度)getcontext().prec = 6 # 保留6位有效数字getcontext().rounding = ROUND_HALF_UP # 银行家舍入a = Decimal('0.1') # 必须用字符串初始化b = Decimal('0.2')print(a + b) # 输出 0.3(精确结果)print(Decimal(0.1)) # 错误示范!会继承二进制浮点误差适用场景:
金融交易系统
税务计算
高精度测量数据
性能代价:
比普通浮点运算慢约10倍
内存占用增加约3倍
from fractions import Fraction a = Fraction(1, 10) # 1/10b = Fraction(2, 10) # 1/5print(a + b) # 输出 3/10print(float(a + b)) # 转换为浮点数 → 0.3
最佳实践:
分子分母不超过10^6时效率最佳
配合sympy库可进行符号运算
适合需要保持分数形式的场景(如化学计量)
# 以分为单位处理金额price = 19.99scaled_price = int(round(price * 100)) # → 1999# 计算总金额total = scaled_price * 3 # 5997 分print(f"总额:{total // 100}.{total % 100:02d} 元") # 59.97元优势:
计算速度比Decimal快100倍
内存效率最高
适合高频交易系统
import numpy as np# 使用128位浮点数(精度≈34位小数)a = np.float128('0.1')b = np.float128('0.2')print(a + b) # 精确输出0.3# 注意:Windows系统可能不支持float128性能对比:
| 数据类型 | 精度(位) | 内存占用 | 计算速度 |
|---|---|---|---|
| float64 | 15-17 | 8字节 | 1× |
| float128 | 33-36 | 16字节 | 0.5× |
| Decimal | 可配置 | 变长 | 0.1× |
def is_close(a, b, rel_tol=1e-9, abs_tol=0.0): return abs(a - b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)print(is_close(0.1 + 0.2, 0.3)) # True# Python 3.5+ 内置方案import mathprint(math.isclose(0.1 + 0.2, 0.3)) # True
参数选择标准:
常规计算:rel_tol=1e-9
工程测量:rel_tol=1e-6
科学计算:rel_tol=1e-12
x = 0.1 + 0.2 # 0.30000000000000004# 方案1:限制显示位数print(f"{x:.2f}") # 0.30# 方案2:智能格式(自动处理末尾零)print("{0:.15g}".format(x)) # 0.3# 方案3:精确字符串表示print(repr(Decimal(x))) # '0.3000000000000000444089209850062616169452667236328125'格式化代码对比:
| 格式说明符 | 示例输入 | 输出结果 | 特点 |
|---|---|---|---|
| :.2f | 0.30000004 | 0.30 | 强制两位小数 |
| :.15g | 0.30000004 | 0.3 | 自动省略无效零 |
| !r | Decimal(0.1) | Decimal('0.1') | 保留完整精度信息 |
from sympy import Rational, N a = Rational(1, 10) # 1/10b = Rational(2, 10) # 1/5exact_sum = a + b # 3/10# 转换为任意精度浮点print(N(exact_sum, 50)) # 0.30000000000000000000000000000000000000000000000000
典型应用场景:
数学证明推导
公式符号处理
需要保留精确中间结果的计算
import jsonfrom decimal import Decimalclass DecimalEncoder(json.JSONEncoder):
def default(self, obj):
if isinstance(obj, Decimal):
return str(obj) # 或float(obj)根据需求选择
return super().default(obj)data = {"price": Decimal('19.99')}json_str = json.dumps(data, cls=DecimalEncoder) # {"price": "19.99"}注意事项:
数据库存储推荐使用DECIMAL类型
避免直接序列化二进制浮点数
CSV输出建议转换为字符串
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/69961576/viewspace-3082974/ ,如需转载,请注明出处,否则将追究法律责任。