首页 » PHP教程 » phproundhalfeven技巧_建议少看垃圾博客以及若安在Python里精确地四舍五入

phproundhalfeven技巧_建议少看垃圾博客以及若安在Python里精确地四舍五入

访客 2024-12-14 0

扫一扫用手机浏览

文章目录 [+]

这位初学者的问题是:

在Python中,如何精确地进行浮点数的四舍五入,保留两位小数?

phproundhalfeven技巧_建议少看垃圾博客以及若安在Python里精确地四舍五入

如果你在Google或者百度上搜索,你会创造大量的来自CSDN、百家号、头条号或者简书上面的文章讲到这一点,但是他们的说法无外乎下面几种:

phproundhalfeven技巧_建议少看垃圾博客以及若安在Python里精确地四舍五入
(图片来自网络侵删)
连例子都不举的垃圾文章

如下图所示,

利用round函数

他们举的例子为:

>>> round(1.234, 2)1.23复制代码

这种文章,他只演示了四舍,但是却没有演示五入。
以是如果你代码稍作修正,就会创造有问题:

>>> round(11.245, 2)11.24复制代码先放大再缩小

这种文章轻微好一点,知道多举几个例子:

然而这种文章也是漏洞百出,只要你多考试测验几个数字就会创造问题,在Python 2和Python 3下面,效果是不一样的。
先来看看Python 2下面的运行效果:

在Python 2里面,直策应用round,1.125精确到两位小数后为1.13,而1.115精确到两位小数后是1.11。

再来看看Python 3下面的效果:

在Python 3下面,1.125在精确到两位小数往后是1.12。

他举的例子,在Python 3中先放大再缩小,也并不总是精确。

装b货

还有一种装b货,文章和先放大再缩小差不多,但是他还知道decimal这个模块。

不过他的利用方法,大家看他吧

详细缘故原由不详 ????

不推举利用这个方法???

这种人要先装个逼,表示自己知道有这样一个库,但是用起来创造有问题,而且不知道缘故原由,以是不建议大家利用。

decimal是专门为高精度打算用的模块,他竟然说不建议大家利用???

round到底出了什么问题?

骂完了,我们来说说,在Python 3里面,round这个内置的函数到底有什么问题。

网上有人说,由于在打算机里面,小数是禁绝确的,例如1.115在打算机中实际上是1.1149999999999999911182,以是当你对这个小数精确到小数点后两位的时候,实际上小数点后第三位是4,以是四舍五入,因此结果为1.11。

这种说法,对了一半。

由于并不是所有的小数在打算机中都是禁绝确的。
例如0.125这个小数在打算机中便是精确的,它便是0.125,没有省略后面的值,没有近似,它确确实实便是0.125。

但是如果我们在Python中把0.125精确到小数点后两位,那么它的就会变成0.12:

>>> round(0.125, 2)0.12复制代码

为什么在这里四舍了?

还有更奇怪的,另一个在打算机里面能够精确表示的小数0.375,我们来看看精确到小数点后两位是多少:

>>> round(0.375, 2)0.38复制代码

为什么这里又五入了?

由于在Python 3里面,round对小数的精确度采取了四舍六入五成双的办法。

如果你写过大学物理的实验报告,那么你该当会记得老师讲过,直策应用四舍五入,末了的结果可能会偏高。
以是须要利用奇进偶舍的处理方法。

例如对付一个小数a.bcd,须要精确到小数点后两位,那么就要看小数点后第三位:

如果d小于5,直接舍去如果d大于5,直接进位如果d即是5: d后面没有数据,且c为偶数,那么不进位,保留c d后面没有数据,且c为奇数,那么进位,c变成(c + 1) 如果d后面还有非0数字,例如实际上小数为a.bcdef,此时一定要进位,c变成(c + 1)

关于奇进偶舍,有兴趣的同学可以在维基百科搜索这两个词条:数值修约和奇进偶舍。

以是,round给出的结果如果与你设想的不一样,那么你须要考虑两个缘故原由:

你的这个小数在打算机中能不能被精确储存?如果不能,那么它可能并没有达到四舍五入的标准,例如1.115,它的小数点后第三位实际上是4,当然会被舍去。
如果你的这个小数在打算机中能被精确表示,那么,round采取的进位机制是奇进偶舍,以是这取决于你要保留的那一位,它是奇数还是偶数,以及它的下一位后面还有没有数据。
如何精确进行四舍五入

如果要实现我们数学上的四舍五入,那么就须要利用decimal模块。

如何精确利用decimal模块呢?

看官方文档,不要看中文垃圾博客!


看官方文档,不要看中文垃圾博客!


看官方文档,不要看中文垃圾博客!


不要担心看不懂英文,Python已经推出了官方中文文档(有些函数的利用方法还没有翻译完成)。

我们来看一下:docs.python.org/zh-cn/3/lib…

官方文档给出了详细的写法:

>>>Decimal('1.41421356').quantize(Decimal('1.000'))Decimal('1.414')复制代码

那么我们来测试一下,0.125和0.375分别保留两位小数是多少:

>>> from decimal import Decimal>>> Decimal('0.125').quantize(Decimal('0.00'))Decimal('0.12')>>> Decimal('0.375').quantize(Decimal('0.00'))Decimal('0.38')复制代码

怎么结果和round一样?我们来看看文档中quantize的函数原型和文档解释:

这里提到了可以通过指定rounding参数来确定进位办法。
如果没有指定rounding参数,那么默认利用高下文供应的进位办法。

现在我们来查看一下默认高下文中的进位办法是什么:

>>> from decimal import getcontext>>> getcontext().rounding'ROUND_HALF_EVEN'复制代码

如下图所示:

ROUND_HALF_EVEN实际上便是奇进偶舍!
如果要指定真正的四舍五入,那么我们须要在quantize中指定进位办法为ROUND_HALF_UP:

>>> from decimal import Decimal, ROUND_HALF_UP>>> Decimal('0.375').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('0.38')>>> Decimal('0.125').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('0.13')复制代码

现在看起来统统都正常了。

那么会不会有人进一步追问一下,如果Decimal吸收的参数不是字符串,而是浮点数会怎么样呢?

来实验一下:

>>> Decimal(0.375).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('0.38')>>> Decimal(0.125).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('0.13')复制代码

那是不是解释,在Decimal的第一个参数,可以直接传浮点数呢?

我们换一个数来测试一下:

>>> Decimal(11.245).quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('11.24')>>> Decimal('11.245').quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)Decimal('11.25')复制代码

为什么浮点数11.245和字符串'11.245',传进去往后,结果不一样?

我们连续在文档在探求答案。

官方文档已经很清楚地解释了,如果你传入的参数为浮点数,并且这个浮点值在打算机里面不能被精确存储,那么它会先被转换为一个禁绝确的二进制值,然后再把这个禁绝确的二进制值转换为等效的十进制值。

对付不能精确表示的小数,当你传入的时候,Python在拿到这个数前,这个数就已经被转成了一个禁绝确的数了。
以是你虽然参数传入的是11.245,但是Python拿到的实际上是11.244999999999...。

但是如果你传入的是字符串'11.245',那么Python拿到它的时候,就能知道这是11.245,不会提前被转换为一个禁绝确的值,以是,建议给Decimal的第一个参数传入字符串型的浮点数,而不是直接写浮点数。

总结,如果想实现精确的四舍五入,代码该当这样写:

from decimal import Decimal, ROUND_HALF_UPorigin_num = Decimal('11.245')answer_num = origin_num.quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)print(answer_num)复制代码

运行效果如下图所示:

特殊把稳,一旦要做精确打算,那么就不应该再单独利用浮点数,而是该当总是利用Decimal('浮点数')。
否则,当你赋值的时候,精度已经被丢失了,建议全程利用Decimal举例:

a = Decimal('0.1')b = Decimal('0.2')c = a + bprint(c)复制代码

末了,

整理了一套最新的python系统学习教程,

想要这些资料的可以关注私信小编“01”即可(免费分享哦)希望能对你有所帮助

标签:

相关文章

大数据片桶,开启智能时代的新篇章

随着科技的飞速发展,大数据已经成为各行各业的重要基石。在众多大数据应用中,大数据片桶作为一种新兴的技术,正逐渐崭露头角,为我国智能...

PHP教程 2024-12-16 阅读0 评论0

大数据百校,开启教育新时代的智慧引擎

随着信息技术的飞速发展,大数据时代已经来临。在我国,大数据应用已经渗透到各行各业,其中教育领域更是迎来了前所未有的变革。近年来,大...

PHP教程 2024-12-16 阅读0 评论0

大数据码,新时代科技创新的驱动力

随着互联网、物联网、云计算等技术的飞速发展,大数据码作为一种新兴的技术手段,逐渐成为新时代科技创新的重要驱动力。大数据码技术具有编...

PHP教程 2024-12-16 阅读0 评论0