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))

执行结果

 

posted @ 2023-01-10 11:22  码上测  阅读(56)  评论(0编辑  收藏  举报