Python_封装四舍五入函数
精度问题产生原因
运行时精度问题在Python中(其他语言中也存在这个问题,这是计算机采用二进制导致的),有时候由于二进制和十进制之间对应问题会导致数值的精度问题,比如无法用有限个二进制位完整地表示0.1,因为0.1转化为二进制之后位一个无限循环小数,
这就导致了四舍五入会因为精度问题得到不符合预期的结果
round函数的精度问题
round函数虽然是内置函数,但是不推荐使用,因为float类型存在精度问题,所以使用该函数可能得不到预期的结果
a = 1.23456 b = 2.355 c = 3.5 d = 2.5 print(round(a, 3)) print(round(b, 2)) print(round(c)) print(round(d))
python3执行结果
从执行结果可以看出b、d的处理结果是有问题的
Decimal函数的精度问题
该函数也不推荐使用,同样存在精度问题
from decimal import Decimal a = Decimal('5.026').quantize(Decimal('0.00')) b = Decimal('3.555').quantize(Decimal('0.00')) c = Decimal('3.545').quantize(Decimal('0.00')) print(a) print(b) print(c)
python3执行结果
从执行结果可以看出c的处理结果是有问题的
封装函数解决精度问题
实现思路
只要使用了浮点数计算就可能产生精度问题,所以在解决精度问题的计算过程中只涉及到整数计算
def handle_round(data, num=0): """ data: 处理的数据 num: 四舍五入保留的小数位数 """ data = str(data) # 如果不是小数直接返回 if "." not in data: return int(data) data_l = data.split(".") d_int = data_l[0] # 整数部分 d_decimal = data_l[1] # 小数部分 # 若小数长度小于等于四舍五入的情况,则不处理 if len(d_decimal) <= num: return float(data) # 获取四舍五入的判断值 handle_num = d_decimal[num] # 【处理取整的四舍五入】 if num == 0: # 1.不需要进位的情况 if int(handle_num) < 5: return int(d_int) # 2.需要进位的情况 # 如果源数据大于0,则+1,反之-1 if float(data) > 0: return int(d_int) + 1 else: return int(d_int) - 1 # 【处理小数的四舍五入】 # 获取四舍五入判断值之前的小数值 handle_num_before = d_decimal[:num] # 1.不需要进位的情况 if int(handle_num) < 5: return float(d_int + "." + handle_num_before) # 小数部分以0开头,转成数字后会被省略,用例0填充还原长度 handle_ret = str(int(handle_num_before) + 1).zfill(len(handle_num_before)) # 2.进位+1后长度不变的情况 if len(handle_ret) == len(handle_num_before): return float(d_int + "." + handle_ret) # 3.进位+1后长度变长的情况。(变长例子:比如0.995四舍五入保留2位,handle_num_before为99,进位后变为100) # 如果源数据大于0,则+1,反之-1 if float(data) > 0: return float(int(d_int) + 1) else: return float(int(d_int) - 1) if __name__ == '__main__': print("取整数") print(handle_round(0.6)) print(handle_round(-0.6)) print(handle_round(0.4)) print(handle_round(-0.4)) print("位数不够四舍五入") print(handle_round(2.5, 2)) print(handle_round(-2.5, 2)) print("四舍") print(handle_round(1.554, 2)) print(handle_round(0.554, 2)) print(handle_round(-0.554, 2)) print("五入") print(handle_round(2.555, 2)) print(handle_round(0.555, 2)) print(handle_round(-0.555, 2)) print("五入后刚好进位") print(handle_round(1.9999, 2)) print(handle_round(-1.9999, 2)) print("小数位以0开始") print(handle_round(1.055, 1)) print(handle_round(-0.0099, 2)) print("整数部分为0,四舍五入后进1") print(handle_round(0.9999, 2)) print(handle_round(-0.9999, 2)) print("可传入字符串") print(handle_round('5.0265', 2)) print(handle_round('-5.0265', 2))
执行结果