马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
最近看了很多关于round()函数带来的四舍五入不精确性的解决方案,最常见的就是乘以10的需要保留的小数位数次幂然后进行的一些列操作比如:
[已解决]python3怎么精确四舍五入保留两位小数?
(出处: 鱼C论坛)中>>> num = 6.655
>>> num = (num * 100 + 0.5) / 100
>>> num
6.66
但这种方案,如果 num = 6.654
结果就变成了>>> num = 6.654
>>> num = (num * 100 + 0.5) / 100
>>> num
6.659
运算结果是直接把数值结果都给更改了,这算解决了吗?并没有
再比如:
【学习笔记】四舍五入的方法,比小甲鱼的有效多了!
(出处: 鱼C论坛)一文中的解决方案是
看,结果和你想象的不一样吧!
要做到真正的四舍五入,应该这样: def new_round(x, dight=0):
temp_dight = 0.5 * (0.1 ** dight)
temp_number = x * (10 ** dight)
number = int(temp_number + temp_dight)
return number / (10 ** dight)
>>> new_round(5.99)
6.0
>>> new_round(4.22, 1)
4.2
>>> new_round(5.5)
6.0
>>>
看似没有问题,于是我试了试new_round(2.67,1)>>> new_round(2.67,1)
2.6
好家伙,这是怎么回事?2.65没四舍五入成功还好说,2.67都没成功还真有点说不过去了
仔细一推敲完全就是错误的函数(0.5完全没能成功的加在末位上啊)
于是我把它修改了下:>>> def new_round(x, dight=0):
temp_dight = 0.5 * (0.1 ** dight)
temp_number = x * (10 ** dight)
number = int((x+ temp_dight)*(10**dight))/(10**dight)
return number
>>> new_round(2.66564,3)
2.666
>>> new_round(2.67,2)
2.67
>>> new_round(2.67,1)
2.7
>>> new_round(0.5,1)
0.5
>>> new_round(0.5,0)
1.0
>>> new_round(2.66544,3)
2.665
这下貌似对了但是仔细想想,这不还是小甲鱼老师教的末位加0.5吗?我只能说同学不细心,你还是没有小甲鱼老师厉害啊。。。。
可是这样就是正确的算法了吗?答案是。。。。还是不行的!
>>> new_round(1.115,2)
1.11
尴尬了。。。。难道就没有算法,把这个头痛的四舍五入通吃掉的吗?
———————————————————————————————这是分割线 ————————以下是和大家探讨的两个算法———————————————————————————————————————————
查阅了网上的资料,在一篇python 准确进行四舍五入的问题,头痛!
一文中,有这么个算法def new_round(_float, _len):
"""
Parameters
----------
_float: float
_len: int, 指定四舍五入需要保留的小数点后几位数为_len
Returns
-------
type ==> float, 返回四舍五入后的值
"""
if isinstance(_float, float):
if str(_float)[::-1].find('.') <= _len:
return(_float)
if str(_float)[-1] == '5':
return(round(float(str(_float)[:-1]+'6'), _len))
else:
return(round(_float, _len))
else:
return(round(_float, _len))
这个算法中,我不太理解
if isinstance(_float, float):
【算法一】为什么要判断其是否为浮点型呢?,于是我加上我自己的理解把上述算法修改成如下:def new_round(_float=float(0),_lens=int(2)):
'''
对输入的_float做四舍五入运算,并输出结果
args:
_float:需要四舍五入的数字,为浮点数
_len:保留小数位数,默认=2,为整形
-----------------
return:
返回Decimal格式的结果
'''
if str(_float)[::-1].find('.') <= _lens: #小数点后位数 比 保留小数位 小于或等于 时 直接四舍五入等于原值
_float = round(_float,_lens)
return _float
elif str(_float)[str(_float)[:].find('.')+_lens+1] == '5': #小数点后位数 比 保留小数位 大 且保留小数位后1位为5时
y = str(_float)[:str(_float)[:].find('.')+_lens+1] + '6'+str(_float)[str(_float)[:].find('.')+_lens+2:] #将该位变成6
_float = round(float(y), _lens)
return _float
else: #小数点后位数 比 保留小数位 大 且保留小数位后1位不为5时 直接四舍五入
_float = round(_float,_lens)
return _float
>>> new_round(1.115,2)
1.12
>>> new_round(1.115,3)
1.115
>>> new_round(1.1156,3)
1.116
>>> new_round(1.1155,3)
1.116
>>> new_round(0.5,0)
1.0
>>>
[b]
[/b]
另一篇python3:小数位的四舍五入(用两种方法解决round 遇5不进)中有这么一种算法:from _pydecimal import Decimal, Context, ROUND_HALF_UP
print(Context(prec=3, rounding=ROUND_HALF_UP).create_decimal('1.325'))
打印结果:
1.33
【算法二】为什么要prec=3,这种很难控制的量作为函数值呢,于是我加上我自己的理解把上述算法修改成如下:def new_round_dec(_float=float, _len=2):
'''
对输入的_float做四舍五入运算,并输出结果
args:
_float:需要四舍五入的数字,为浮点数
_len:保留小数位数,默认=2,为整形
-----------------
return:
返回Decimal格式的结果
'''
if str(_float).find('.') == -1:
return _float
else:
# prec= (str(_float).find('.')+_len),整数部分加+小数点+保留位数=从左至右保留字符串长度
#rounding=ROUND_HALF_UP 取舍方式采取四舍五入方式
#.create_decimal(str(_float)) 创建一个decimal格式的值
return Context(prec=(str(_float).find('.')+_len), rounding=ROUND_HALF_UP).create_decimal(str(_float))
>>> from decimal import *
>>> new_round_dec(1.1235654,4)
Decimal('1.1236')
>>> new_round_dec(1.1235654,5)
Decimal('1.12357')
>>> new_round_dec(1313.1235654,6)
Decimal('1313.123565')
>>> new_round_dec(1313.1235654,7)
Decimal('1313.1235654')
以上两种算法:
一是算法一中if isinstance(_float, float):判断其是否为浮点型的必要性,我觉得似乎没有必要
二是这两种算法,有没有,没有想周全的地方和存在问题的地方
欢迎大家探讨,指出,谢谢!
|