Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >为什么你需要少看中文技术博客以及如何在Python里面精确四舍五入

为什么你需要少看中文技术博客以及如何在Python里面精确四舍五入

作者头像
青南
发布于 2019-04-25 06:43:19
发布于 2019-04-25 06:43:19
71500
代码可运行
举报
文章被收录于专栏:未闻Code未闻Code
运行总次数:0
代码可运行

今天又有一个Python初学者被中文技术博客中的垃圾文章给误导了。

这位初学者的问题是:

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

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

连例子都不举的垃圾文章

如下图所示,懒得吐槽。

使用round函数

他们举的例子为:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> round(1.234, 2)1.23

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> round(11.245, 2)11.24

先放大再缩小

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

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

在Python 2里面,直接使用 round1.125精确到两位小数后为 1.13,而 1.115精确到两位小数后是 1.11

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

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

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

装逼货

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

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

具体原因不详 ????

不推荐使用这个方法???

这种人要先装个逼,表示自己知道有这样一个库,但是用起来发现有问题,而且不知道原因,所以不建议大家使用。

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

round到底出了什么问题?

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

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

这种说法,对了一半。

因为并不是所有的小数在计算机中都是不精确的。例如 0.125这个小数在计算机中就是精确的,它就是 0.125,没有省略后面的值,没有近似,它确确实实就是 0.125

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> round(0.125, 2)0.12

为什么在这里 四舍了?

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> round(0.375, 2)0.38

为什么这里又 五入了?

因为在Python 3里面, round对小数的精确度采用了 四舍六入五成双的方式。

如果你写过大学物理的实验报告,那么你应该会记得老师讲过,直接使用四舍五入,最后的结果可能会偏高。所以需要使用 奇进偶舍的处理方法。

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

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

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

所以, round给出的结果如果与你设想的不一样,那么你需要考虑两个原因:

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

如何正确进行四舍五入

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

如何正确使用decimal模块呢?

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

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

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

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

我们来看一下:https://docs.python.org/zh-cn/3/library/decimal.html#decimal.Decimal.quantize

官方文档给出了具体的写法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>>Decimal('1.41421356').quantize(Decimal('1.000'))Decimal('1.414')

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> 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参数,那么默认使用上下文提供的进位方式。

现在我们来查看一下默认上下文中的进位方式是什么:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> from decimal import getcontext>>> getcontext().rounding'ROUND_HALF_EVEN'

如下图所示:

ROUND_HALF_EVEN实际上就是 奇进偶舍!如果要指定真正的四舍五入,那么我们需要在 quantize中指定进位方式为 ROUND_HALF_UP

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> 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接收的参数不是字符串,而是浮点数会怎么样呢?

来实验一下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> 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的第一个参数,可以直接传浮点数呢?

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
>>> 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的第一个参数传入字符串型的浮点数,而不是直接写浮点数。

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
from decimal import Decimal, ROUND_HALF_UP
origin_num = Decimal('11.245')answer_num = origin_num.quantize(Decimal('0.00'), rounding=ROUND_HALF_UP)print(answer_num)

运行效果如下图所示:

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

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
a = Decimal('0.1')b = Decimal('0.2')c = a + bprint(c)

总之,你遇到的绝大部分问题,在官方文档里面都能找到原话,多到文档中寻找答案,少看装逼货的垃圾博客。

最后,如果有同学想知道为什么0.125和0.375能被精确的储存,而1.115、11.245不能被精确储存,请在这篇文章下面留言,如果想知道的同学多,我就写一篇文章来说明。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-03-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 未闻Code 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
如何在 Python 里面精确四舍五入?
花下猫语:如何精确地计算浮点数?这是计算机科学的大难题。那 Python 是如何处理浮点数的四舍五入问题的呢?今天分享的文章,对此展开了深入的剖析。
Python猫
2019/04/23
5.1K0
如何在 Python 里面精确四舍五入?
python小数的进位与舍去
在python中进行精确的数值运算时,一般采用decimal模块对小数进行运算,其中用到了,十进制数decimal number, context算数上下文参数, signals信号信息
py3study
2020/01/16
1.8K0
Python之谜:四舍五入round(4.5)等于4?
你好,我是zhen guo! 四舍五入4.5,应该返回结果5,但是使用Python或NumPy内置的round方法计算,结果都返回结果4 先来还原一下: In [1]: round(4.5) Out[1]: 4 In [2]: import numpy as np In [3]: np.round(4.5) Out[3]: 4.0 如果再看一个例子,四舍五入保留小数点后1位,发现它又是进位的: In [1]: round(4.15,1) Out[1]: 4.2 round背后 Python的round使用
double
2022/09/26
1.8K0
Python3 四舍五入问题详解
“就本质来说,浮点算术是不精确的,而且程序员们很容易滥用它,从而使计算的结果几乎全部由噪声组成”
用户9077582
2021/10/11
3.5K0
在Python里想要四舍五入有多麻烦?
然而让人没想到的是,一个简单的四舍五入操作,在Python里居然这么难搞,网上还一堆错误的教程。
Crossin先生
2024/03/26
1660
在Python里想要四舍五入有多麻烦?
Python 的四舍五入的两个方法
大多数情况下,我们会使用 round 来保留小数,但这并不符合我们在数学知识里的规则。
somenzz
2022/10/25
8350
python知识点100篇系列(11)-浮点数四舍五入的两种方法
JQ实验室
2024/09/25
1540
浮点数精度不再是困扰:Python高手的精准编程秘籍!解决Python浮点数精度问题!
这里的问题在于,0.1 和 0.2 在二进制中都是无限循环小数,计算机只能存储它们的近似值。当这两个近似值相加时,结果也是一个近似值,这个近似值可能并不完全等于我们期望的十进制结果。
小白的大数据之旅
2024/11/20
2300
【测试开发】python系列教程:decimal库
Python decimal库是Python标准库中的一部分,用于处理数字货币和金融交易。它提供了一个完整的货币处理API,可以处理各种货币常见的业务,如货币兑换、汇率计算、支付处理等。
雷子
2023/08/21
3570
【测试开发】python系列教程:decimal库
java 四舍五入保留小数的几种方式
(new BigDecimal()).setScale()方法用于格式化小数点,有多种小数保留模式,如下:
全栈程序员站长
2022/08/31
2.5K0
只取小数点后两位函数公式_js四舍五入保留两位小数
大家好,我是架构君,一个会写代码吟诗的架构师。今天说一说只取小数点后两位函数公式_js四舍五入保留两位小数,希望能够帮助大家进步!!!
Java架构师必看
2022/04/30
4.3K0
python中四舍五入,颠覆你的想象
上一节知识点主要讲到了进制转换,这一块其实属于计算机基础课程。在Python中主要涉及到:
刘金玉编程
2019/08/26
6610
Python 四舍五入函数 round
这个与计算机系统的设计是有关系的,计算机是使用 2 进制进行计算的的,如果我们常用的数学计算或者科学计算,计算机是会丢精度的。
HoneyMoose
2020/06/02
9820
Python 四舍五入
但是我在一次实验中还是发现了不正确的四舍五入,暂时没有复现,使用的时候还是要多加小心。
为为为什么
2024/08/24
1400
Java基础知识点笔记(一):java中的取整与四舍五入
今天编码时,需要对数据进行保留两位小数处理,结果卡壳了,百度了一下解决掉后,结果返回到前端的值不是预想值,特此整理,以备后续遗忘。
全栈程序员站长
2022/09/08
3.4K0
Java基础知识点笔记(一):java中的取整与四舍五入
【Go】四舍五入在go语言中为何如此困难
四舍五入是一个非常常见的功能,在流行语言标准库中往往存在 Round 的功能,它最少支持常用的 Round half up 算法。
thinkeridea
2021/01/04
1.4K0
java保留两位小数
四舍五入   double   f   =   111231.5585;   BigDecimal   b   =   new   BigDecimal(f);   double   f1   =   b.setScale(2,   BigDecimal.ROUND_HALF_UP).doubleValue();   保留两位小数 ---------------------------------------------------------------
bear_fish
2018/09/19
6.3K0
万字长文,史上最全Python字符串格式化讲解
今天分享的是一篇来自群友小王(王暖暖)同学的投稿,可以说是非常的细节,堪称史上最全对字符串格式化输出的讲解了!
可以叫我才哥
2022/04/12
4.7K0
万字长文,史上最全Python字符串格式化讲解
如何在 JavaScript 中将数字四舍五入到小数点后两位
英文 | https://codingbeauty.medium.com/javascript-round-number-to-2-decimal-places-3537ad0736f7
winty
2023/01/09
2.9K1
python 怎么保留小数「建议收藏」
大部分语言都可以使用字符串格式化的方法来实现保留两位小数的效果,python也不例外:
全栈程序员站长
2022/09/21
9060
推荐阅读
相关推荐
如何在 Python 里面精确四舍五入?
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验