「四舍五入」是小学就学过的数学知识,也是日常计算中经常会用到的处理方法。
然而让人没想到的是,一个简单的四舍五入操作,在Python里居然这么难搞,网上还一堆错误的教程。
来看这个例子,有一个变量a为1.135,现在希望把它保留2位小数,要怎么做?
网上搜索一下,找到两种方法:
第1种,round函数。第一个参数是原数字,第二个参数是要保留的小数位数
round(a, 2)
结果 1.14,没有问题。
第2种,通过格式说明符.f对浮点数进行字符串格式化,f前加上要保留的小数位数。
这种写法在 %格式化、format方法和f-string 上均适用。
print('%.2f' % a, '{:.2f}'.format(a), f'{a:.2f}')
结果 1.14,也没有问题。
所以看来,以上两种方法都可以实现四舍五入地保留小数位数……

but,真的是这样吗?
显然事情没这么简单。如果把a的值改成1.125,再跑一下之前的代码,就发现两种方法都不对了。

别小看这么一点误差,我曾经在做助教时,就因为类似的原因,导致一位原本算好被60分放过的同学挂了科。

有些不靠谱的半瓶水教程会跟你说,这是因为Python用了种叫做「四舍六入五成双」的保留机制:5前面的数字是奇数就进位,是偶数就保持不变,所以1.135会得到1.14,而1.125就是1.12。

还有的教程告诉你有种方法可以实现四舍五入:就是把要保留N位的小数,乘以10的N次方,加上0.5后取整,再除以10的N次方
int(a * 10 ** 2 + 0.5) / 10 ** 2)
结果确实是 1.13。
但你以为这样就可以了吗?
如果再把a改成1.035。结果既没有什么所谓的奇数进位,也没能通过先乘再除的方法实现四舍五入。

把1.005,1.015,1.025,一直到1.995,用前面提到过的3种方法保留2位小数的结果输出出来就会发现。round和字符串格式化得到的保留结果是一样的,且基本没有规律可言。
而先乘后除法虽然在大部分情况下是符合四舍五入的,但仍然有一些例外的情况。



导致这种现象的原因,和之前讲解过的 0.1 + 0.2 != 0.3 一样,都是因为浮点数的精度造成的。
让这些小数输出更多位数,就会看到,很多值虽然结尾是5,但在计算机中以二进制存储的实际值其实不到5。那么按照四舍五入来说,当然是要被舍去了。

真正可以做到对小数保留位数进行精确控制的方法是使用 Python 内置的 decimal 模块,它用于高精度的十进制算术运算。
用 round 函数对于 Decimal 类型对象进行保留,才是真正的四舍六入五成双。
from decimal import Decimal
x = 1.035
print(round(Decimal(str(x)), 2))

这种机制又被称作「银行家舍入」,它其实比四舍五入更合理。因为5是两个数的中间值,全都进位会让数据在整体分布上偏大,而银行家舍入规则可以让累积误差趋向于0。
如果你就是想要按照四舍五入来保留,也可以,通过将 Context 里的 rounding 属性设置为 ROUND_HALF_UP 就可以
from decimal import Decimal, ROUND_HALF_UP, getcontext
x = 1.045
getcontext().rounding = ROUND_HALF_UP
print(round(Decimal(str(x)), 2))
另一种写法是通过 Decimal 的 quantize 方法,指定保留位数和舍入规则,效果是一样的。
from decimal import Decimal
x = 1.045
print(Decimal(str(x)).quantize(Decimal('0.01'), rounding='ROUND_HALF_UP'))
这样,就能完美地按四舍五入保留小数了。
不过这里还有一个小小的坑,就是一定要通过字符串去创建 Decimal 对象,否则实际值仍然是带有误差的,从而导致四舍五入失效。

好吧,没想到一个简单的四舍五入操作,竟然还这么复杂,你学会了吗?
关于Python学习指南
学好 Python 不论是就业还是做副业赚钱都不错,但要学会 Python 还是要有一个学习规划。最后给大家分享一份全套的 Python 学习资料,给那些想学习 Python 的小伙伴们一点帮助!
包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、自动化办公等学习教程。带你从零基础系统性的学好Python!
👉Python所有方向的学习路线👈
Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取)

👉Python学习视频600合集👈
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末
👉Python70个实战练手案例&源码👈
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。

👉Python大厂面试资料👈
我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。


👉Python副业兼职路线&方法👈
学好 Python 不论是就业还是做副业赚钱都不错,但要学会兼职接单还是要有一个学习规划。

👉 这份完整版的Python全套学习资料已经上传,朋友们如果需要可以扫描下方CSDN官方认证二维码或者点击链接免费领取【保证100%免费】
本文揭示了Python中四舍五入操作的复杂性,特别是在处理浮点数精度问题时。作者介绍了round函数、字符串格式化、decimal模块以及银行家舍入等方法,并强调了使用Decimal模块进行精确控制的重要性。
3392

被折叠的 条评论
为什么被折叠?



