大家都知道python3版本的round跟我们平时想象的不一致,在有的时候又需要用传统的round,比如在股票市场计算的时候,涨停价就是在昨收基础上乘以1.1或者1.2,然后round,这个时候的round需要使用传统意义上的四舍五入,否则价格会有差异。
至于python3版本的坑,这里不多说。有的人说会向偶数靠近,有的人说向奇数靠近,其实都是错误的,可以看看下面的例子:
print(round(3.1350001, 2)) # 结果3.14 进位,符合预期
print(round(3.135, 2)) # 结果3.13 不符合预期,谁说的向偶数靠近?
print(round(3.445, 2)) # 结果3.44 不符合预期,谁说的向奇数靠近?
print(round(3.145, 2)) # 结果3.15 进位,符合预期,3.445和3.145得到不同的预期?
print(round(3.535, 2)) # 结果3.54 进位,符合预期,3.135和3.535得到不同的预期?
网上也有说自己加个0.5来取整的算法,伪代码如下(不考虑负数的圆整):
def round(number, ndigits):
return int((number+5*10**(-ndigits-1))*10**ndigits)/10**ndigits
看着好像是对的,但是我们把代码展开后,用3.135来测试一下
def round(number, ndigits):
#number=3.135
#ndigits=2
r = 5*10**(-ndigits-1) # r=0.005
a = number+r # a=3.1399999999999997 就是这里有猫腻,并不是想象的3.14
b = a*10**ndigits # b=313.99999999999994
c = int(b) # c=313
d = c/10**ndigits # d=3.13
return d
其实问题就是浮点计算时,二进制浮点数被截断了,所以导致出现 3.1399999999999997 这样的数据,而不是3.14
所以,综上,网上好多的自定义算法都有问题。
下面给出正确的方法:
def old_round(number, ndigits): # 耗时大概是round的2倍多点
arr = str(number).split('.')
if len(arr) > 1 and len(arr[-1]) > ndigits and '5' == arr[-1][ndigits]:
if number >= 0:
return round(number + 10**(-ndigits-1), ndigits)
else:
return round(number - 10**(-ndigits-1), ndigits)
else:
return round(number, ndigits)
至于Decimal类型,我不想因为一个round而引入这玩意,上面的函数,测试上面的例程,结果均正确。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)