python内置方法round()四舍五入方法问题
2021-10-15 本文已影响0人
洛奇lodge
问题描述
-
最近在项目中数据出现问题,经过排查,原来是round()惹得祸,如下图所示,round()进行保留位数,并不是按照我们数学上的逻辑四舍五入进行保留
- 查看官网https://docs.python.org/zh-cn/3/library/functions.html?highlight=round#round,可以看出,这个并不是round函数错误,只能说浮点数在计算机存储是比较特殊,如传入参数
2.675
,实际计算存储是2.67499999999...
, 所以在保留位数时候就会出现问题
问题解决
- 方案一
def new_round(_float, _len):
"""
判断需要保留位数后的一位是不是5,如果是5,变成6,在使用round进行四舍五入
:param _float:
:param _len:
:return:
"""
if isinstance(_float, float) or isinstance(_float, np.float):
# 小数位数小于保留长度, 直接返回
if str(_float)[::-1].find('.') <= _len:
return _float
if str(_float).split('.')[1][_len] == '5':
_float = float(str(_float).split('.')[0] + '.' + str(_float).split('.')[1][:_len]+'6')
elif isinstance(_float, pd.Series):
_float = _float.apply(lambda x: float(str(x).split('.')[0] + '.' + str(x).split('.')[1][:_len]+'6') \
if len(str(x).split('.'))==2 and len(str(x).split('.')[1])>_len and str(x).split('.')[1][_len] == '5' \
else x)
return round(_float, _len)
- 方案二
def new_round(_float, _len):
"""
通过Decimal模板进行精确度处理四舍五入
传入Decimal参数必须是字符串,才能生效
:param _float:
:param _len:
:return:
"""
_len_str = '0.' + '0' * _len
if isinstance(_float, float) or isinstance(_float, np.float):
_float = float(Decimal(str(_float)).quantize(Decimal(_len_str), rounding=ROUND_HALF_UP))
elif isinstance(_float, pd.Series):
_float = _float.apply(lambda x: float(Decimal(str(x)).quantize(Decimal(_len_str), rounding=ROUND_HALF_UP)))
return _float