抛出问题

输出:

why?奇进偶舍

转载:https://cloud.tencent.com/developer/article/1426211

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,需要精确到小数点后两位,那么就要看小数点后第三位:

  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已经推出了官方中文文档(有些函数的使用方法还没有翻译完成)。

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

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

>>>Decimal('1.41421356').quantize(Decimal('1.000'))
Decimal('1.414')

那么我们来测试一下,0.1250.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 + b
print(c)

最后附上python中的舍入模式

Decimal.quantize相关推荐

  1. python decimal用法_Python decimal模块使用方法详解

    decimal 模块:decimal意思为十进制,这个模块提供了十进制浮点运算支持 1.可以传递给Decimal整型或者字符串参数,但不能是浮点数据,因为浮点数据本身就不准确. 2.要从浮点数据转换为 ...

  2. Python中的Decimal

    文章目录 1.可以传递给Decimal整型或者字符串参数,但不能是浮点数据,因为浮点数据本身就不准确. 2.要从浮点数据转换为Decimal类型 3.getcontext().prec设置有效数字的个 ...

  3. python decimal 转换为float_在Python中将float转换为decimal类型

    我只是在玩数字游戏. 我发现Numpy提供了一个名为np.vectorize的函数,允许您获取一个函数并将其应用于Numpy数组. 在[23]中:import numpy as np import d ...

  4. 【Python】浮点数计算时的不准确性以及如何进行精确计算

    浮点数一个普遍的问题就是在计算机的世界中,浮点数并不能准确地表示十进制.并且,即便是最简单的数学运算,也会带来不可控制的后果.因为,在计算机的世界中只认识0与1 因为在计算机里面,小数是不精确的,例如 ...

  5. 第一章 Python初探

    目录 一.python类别 二.python编码 2.1 编码类型 2.1.1 ASCII编码 2.1.2 GB2312编码 2.1.3 GBK编码 2.1.4 ANSI(扩展的ASCII编码) 2. ...

  6. python 如何四舍五入

    round()函数-奇进偶舍 奇进偶舍,又称为四舍六入五成双规则.银行进位法. 它是一种计数保留法.从统计学的角度,"奇进偶舍"比"四舍五入"更为精确:在大量运 ...

  7. 深入原理64式:26 python知识总结

    目标: 整理python知识,主要包含如下内容: 1.器(生成器.迭代器.装饰器等) 2.类(元类,多态,方法等) 3.进程池与线程池 4.协程 5.实现原理 6.算法 7.基础 8.python重要 ...

  8. python用format保留三位小数_关于Python 保留小数使用format、%、round()、Decimal函数及format和%只能保留到六位问题...

    Python 保留小数 1.可以使用format内置函数格式化输出 import math PI = math.atan(1.0)*4 # atan(1.0)*4 = π print('{:.7f}' ...

  9. python四舍五入round_Python四舍五入及round、Decimal使用

    Python四舍五入及round.Decimal使用 Python四舍五入大法round和Decimal的比对(默认decimal.ROUND_HALF_EVEN)decimal.ROUND_CEIL ...

最新文章

  1. ASP.NET全球化与本地化 c#多国语言的支持 (项目支持多国语言的开发)
  2. python已经取代了excel_Python已经取代Excel?网友:笑了
  3. MOSS 2007基础:WSS 3.0 中的母版页(Master Pages)和内容页(Content Pages)
  4. Java:检查器框架
  5. css 竖行进度图_前端学习--汇集了大量 CSS 的使用和学习的示例代码
  6. 在将varchar值id转换为int时失败_MySQL令人咋舌的隐式转换
  7. 新型冠状病毒肺炎国内分省分日期从1.16起的全部数据爬取与整理代码(附下载)
  8. IndexedDB基本概念
  9. 每周荐书:SQL优化、深度学习、数据科学家(评论送书)
  10. Android:Android Studio生成签名文件,自动签名,以及获取SHA1和MD5值
  11. 外卖侠小程序源码v4.24.0微擎插件外卖cps同城生活团购
  12. 墨者学院 - IIS写权限漏洞分析溯源
  13. 全国大学生数学竞赛(非数学专业)习题精讲等相关资源
  14. 职业教育迎来新的发展期
  15. JUC(二):Java 线程预备知识
  16. 一份小白前端可视化学习指南——附思维导图
  17. 加州大学圣地亚哥分校计算机科学排名,2020年加州大学圣地亚哥分校排名TFE Times美国最佳计算机科学硕士专业排名第17...
  18. 音频剪辑软件怎么剪切音频
  19. 《卡车模拟器3D》技术支持
  20. Fiddler4.6中文版和Jmeter5.1集成导出

热门文章

  1. TSDF算法原理及源码解析
  2. NYOJ284坦克大战
  3. 基于php目标奖罚管理系统
  4. Win11电脑睡眠后无法唤醒
  5. qq农场服务器显示忙是什么原因,QQ农场关于游戏显示系统繁忙处理方法分享
  6. 随机森林模型sklearn_Sklearn_随机森林
  7. JavaScript 进阶知识 - Ajax篇
  8. 毕业生的礼物 贪心 妙用priority_queue
  9. 抖音播放量为什么那么少?如何提升抖音账号权重?
  10. FAST AND HIGH-QUALITY SINGING VOICE SYNTHESIS SYSTEM BASED ON CONVOLUTIONAL NEURAL NETWORKS