前置场景
在工作中,遇到需要从mysql数据库中查询两个字段,一个为int类型,一个为Decimal类型,计算两者相乘的结果
select a, b from t_data;
# 查询结果{'a': 12346, 'b': Decimal('0.00001')}
踩坑
之前都是用的基础类型int,float啥的直接进行计算,所以也想着转换成float进行计算。
b = float(b)
c = a * b
print(c)
然后一看结果,一脸懵:0.1234600001
分析
试着去写了个demo去复现这个问题,但并没有成功,输出结果无误。
f = 1e-05
i = 12345
print(f*i)
突然想到浮点数计算可能会存在精度损失,就去查了一下float与Decimal互相转换的问题。
Decimal对象是 Python 中用于高精度十进制运算的类。它位于decimal模块中,并提供了精确的十进制计算功能。Decimal对象和浮点数(float)是两种不同的数据类型,它们之间的转换可能会导致精度丢失。float类型是基于二进制浮点数表示,而Decimal对象使用十进制表示。 如果你需要将Decimal对象转换为浮点数,可以使用float函数进行转换。但是请注意,在转换过程中可能会发生精度丢失。 以下是一个示例代码,演示如何将Decimal对象转换为浮点数:
python from decimal import Decimal
# 创建一个 Decimal 对象
decimal_num = Decimal('3.141592653589793')
# 将 Decimal 对象转换为浮点数
float_num = float(decimal_num)
print(decimal_num)
print(float_num)
在上述示例中,我们首先创建了一个Decimal对象decimal_num,然后使用float函数将其转换为浮点数float_num。
请注意,由于十进制和二进制的表示方式不同,转换为浮点数可能会导致精度损失。在进行需要高精度计算的任务时,建议尽量保持使用Decimal对象进行计算,以避免精度丢失。
解决
虽然没办法复现,但大致可以定位为Decimal对象转为float后参与计算导致了精度损失。 我试了一下直接用Decimal参与计算,计算结果果然恢复正常
引申问题
计算问题是解决了,但又引入了新的问题。 计算结果为Decimal类型,无法实现json序列化。 解决方法是将Decimal类型转换为其他可json序列化的类型,如float(已经计算完成,不用担心精度损失),str等