一.控制小数位数的方法
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
,则在字符串左侧填充零直到达到指定的长度。代码已修改。
如果我的想法有误,欢迎大家指出。谢谢各位了。