Python实现四舍五入(精确舍入)

一.控制小数位数的方法

1.round()函数

print(round(2.735, 2))
# 结果:2.73

print(round(2.736, 2))
# 结果:2.74

print(round(2.734,2))
#结果:2.73

2.精度控制

print("----控制精度----")
print(f'{2.735:.2f}')
print(f'{2.736:.2f}')
print(f'{2.734:.2f}')
print(f'{3.145:.2f}')
print(f'{3.146:.2f}')
print(f'{3.135:.2f}')

'''
    结果:
    2.73
    2.74
    2.73
    3.15
    3.15
    3.13
'''

3.Decimal模块

decimal有以下舍入模式

I.decimal.ROUND_DOWN

舍入方向为零。

II.decimal.ROUND_FLOOR

向无限延伸

III.decimal.ROUND_HALF_DOWN

舍入到最接近的数,同样接近则舍入方向为零。

IV.decimal.ROUND_HALF_EVEN

舍入到最接近的数,同样接近则舍入到最接近的偶数。

V.decimal.ROUND_HALF_UP

舍入到最接近的数,同样接近则舍入到零的反方向。

VI.decimal.ROUND_UP

舍入到零的反方向。

VII.decimal.ROUND_05UP

如果最后一位朝零的方向舍入后为 0 或 5 则舍入到零的反方向;否则舍入方向为零。

使用例子如下:

print("----Deciaml----")
from decimal import Decimal, ROUND_HALF_EVEN, getcontext

getcontext().prec = 3  # 设置精度为3位
getcontext().rounding = ROUND_HALF_EVEN  # 设置舍入策略为银行家舍入

x = Decimal('2.735')
rounded_x = round(x, 2)  # 保留两位小数

print(rounded_x)

#结果:2.74

decimal模块会将浮点数精确的转换为十进制数进行操作,所以结果更为准确。

注:getcontext获取上下文环境,我们对其的设置为全局变量

二.原理解释

round()和精度控制,采用的舍入策略都是

IV.decimal.ROUND_HALF_EVEN

舍入到最接近的数,同样接近则舍入到最接近的偶数。

这个策略又称银行家策略,在经济学上,这样的策略能获得更小的误差。

而不是我们习惯的“四舍五入”

另外,大家可能有困惑,使用的例子数字2.735,如果是银行家策略,两位小数舍入,结果应该是2.74。这是因为在计算机里大多数十进制小数实际上都不能以浮点数精确地表示,数值以二进制存入计算机,对于浮点数,不能精确表示。

decimal将其转换为十进制数操作,所以避免了这种情况。

2.735二进制表示为10.10111100001010001111,实际结果出来应该是2.73499965667724609375

三. 达成“四舍五入”

# 两位小数,四舍五入
def decimal(num):
    num_str = str(num)
    integer_Part, dot, decimals_Part = num_str.partition('.')
    length = len(decimals_Part)
    if length > 2:
        decimals_Part_End = decimals_Part[:2]
        # 判断小数位第三位大于等于5
        if int(decimals_Part[2]) >= 5:
            enter_Num = int(decimals_Part_End) + 1
            # 小数位第3位大于5,且进位后长度仍大于2,则整数位进位1
            if len(str(enter_Num)) > 2:
                integer_Part = int(integer_Part) + 1
                integer_Part = str(integer_Part)
                enter_Num = '00'
        else:
            enter_Num = decimals_Part_End
    elif length == 2:
        enter_Num = decimals_Part
    else:
        enter_Num = decimals_Part + '0'
    return integer_Part + dot + str(enter_Num).zfill(2)

partition是将数根据分隔符将数分为三部分,分别存储给a,b,c。

b存储分隔符。

这样我只需要对c(存储小数部分)进行处理

并且判断结果不足两位小数时的情况

  • 2024.2.28  感谢用户麦口胡的指正,对于要判断进制的小数enter_Num,我之前将它强转为int,当小数首位为0时,如1.032,此时enter_Num为032,强转int会导致0丢失变成32.
  • 2024.2.28  代码变量命名与错误已进行修改,很抱歉现在才看到消息,发现这个错误。
  • 2024.2.29 感谢用户jingloveme2的提醒,之前的修改,我粗心的仅对小数不进位的情况进行了修改,导致进位情况下出现了之前丢0的错误。我通过判断强转之后小数位长度的变化来知道,小数部分首位是不是0,进而进行添0操作。
  • 2024.2.29 进位情况已修改
  • 2024.3.2 感谢用户jingloveme2的帮助,学习到了zfill方法,用于在字符串的左侧填充零直到字符串达到指定的长度。方法:string.zfill(width),其中,string 是要进行填充的字符串,width 是最终期望的字符串宽度(长度)。如果字符串的长度小于 width,则在字符串左侧填充零直到达到指定的长度。代码已修改。

如果我的想法有误,欢迎大家指出。谢谢各位了。

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值