菜鸟IT的博客
"菜鸟IT"的博客 (WWW.17WX.NET)
熟悉HTML网站的前端美工到切图制作,搭配DIV+TABLE+CSS,熟悉Fireworks和Dreamwear的网站制作实战应用,专注于学习和记录JS脚本对于网页改造的各种新奇技术.平时的工作既要做销售,也要做前端开发,也要做后期的客户售后维护,此博客为博主自己平时的IT工作的实战学习笔记,记录自己工作和学习中遇到的各种坑,也分享给有需要的新人...
博客首页 网站前端制作 网赚 软件应用 Windows系统 Python
谷歌联盟提供的广告↓
[网站前端制作]有关标签↓
[网赚]有关标签↓
[软件应用]有关标签↓
[Windwos系统]有关标签↓
 | 
菜鸟IT的博客 >> Python

【计算有问题,仅用于错误案例分析】二级制运算的精度丢失,精度误差,导致小数点后四舍五不入,decimal.Context(prec=5,rounding=decimal.ROUND_HALF_UP).create_decimal(str(x)) | 无法求浮点数小数保留小数点的问题
# -*- coding: UTF-8 -*-
# 使用round函数,round函数本身的四舍五入原则是对的。
# 只不过背后的精度问题,导致你表面眼睛看到的是四舍五不入。
# 二进制保存的值有点精度误差导致的。

import decimal
x=110.315
print("查看",x,"使用round函数保留2位小数之后的样子:",round(x,2))
print("查看",x,"的真实样子:",decimal.Decimal(x))

y=1002.145
print("查看",y,"使用round函数保留2位小数之后的样子:",round(y,2))
print("查看",y,"的真实样子:",decimal.Decimal(y))

print("换一种方法对付(不够动态,不够灵活,因为prec参数的值包含了小数点左边的位数):",x,end="→")
print(decimal.Context(prec=3,rounding=decimal.ROUND_HALF_UP).create_decimal(str(x)))
print("换一种方法对付(不够动态,不够灵活,因为prec参数的值包含了小数点左边的位数):",y,end="→")
print(decimal.Context(prec=3,rounding=decimal.ROUND_HALF_UP).create_decimal(str(y)))

# 但是上面函数里的prec是把小数点前面的数字部分的位数全部包含了。
# 这个就需要做判断了。


print("输出x的长度:",len(str(x)))
print("输出y的长度:",len(str(y)))

# 先对x进行分割切片,使用split()函数
# 这种对小数的切片,
x_FenGe=str(x).split(".")
y_FenGe=str(y).split(".")
print(x_FenGe)
print(y_FenGe)
# 比如我想对x保留3位小数,
# 那么我在上面的prec后面的数字应该是切割后小数点前面的部分的位数,加上我想保留的。
# 先计算分割后的列表的第1个元素的位数。
x_XsdLeftWS=len(x_FenGe[0])
y_XsdLeftWS=len(y_FenGe[0])
print("小数点",x,"的左边的数字位数:",x_XsdLeftWS)
print("小数点",y,"的左边的数字位数:",y_XsdLeftWS)

print("换一种方法对付(已经变的灵活,能正常保存我想要的小数点后面的位数了):",x,end="→")
print(decimal.Context(prec=3+x_XsdLeftWS,rounding=decimal.ROUND_HALF_UP).create_decimal(str(x)))
print("换一种方法对付(已经变的灵活,能正常保存我想要的小数点后面的位数了):",y,end="→")
print(decimal.Context(prec=3+y_XsdLeftWS,rounding=decimal.ROUND_HALF_UP).create_decimal(str(y)))


★★★★★——————————
输出结果:



查看 110.315 使用round函数保留2位小数之后的样子: 110.31
查看 110.315 的真实样子: 110.31499999999999772626324556767940521240234375
查看 1002.145 使用round函数保留2位小数之后的样子: 1002.14
查看 1002.145 的真实样子: 1002.14499999999998181010596454143524169921875
换一种方法对付(有隐患,因为prec参数的值包含了小数点左边的位数): 110.315→110
换一种方法对付(有隐患,因为prec参数的值包含了小数点左边的位数): 1002.145→1.00E+3
输出x的长度: 7
输出y的长度: 8
['110', '315']
['1002', '145']
小数点 110.315 的左边的数字位数: 3
小数点 1002.145 的左边的数字位数: 4
换一种方法对付(已经消除隐患,能正常保存我想要的小数点后面的位数了): 110.315→110.315
换一种方法对付(已经消除隐患,能正常保存我想要的小数点后面的位数了): 1002.145→1002.145

进程已结束,退出代码0





最后总结:

要导入库
import decimal
然后

y=decimal.Context(prec=3+len(str(x).split(".")[0]),rounding=decimal.ROUND_HALF_UP).create_decimal(str(x))
其中上面的3就是保留3位小数
x就是开始的小数。

################################################################

于2022年3月25日,偶然一次测试中,发现大问题。怪我自己没测试好。

原始参考代码:
y=decimal.Context(prec=3,rounding=decimal.ROUND_HALF_UP).create_decimal(str(x))
我改进的代码:
z=decimal.Context(prec=3+len(str(x).split(".")[0]),rounding=decimal.ROUND_HALF_UP).create_decimal(str(x))

我多来几个案例,分析下吧:

# ——————————————————

比如x=0.05477
输出结果↓
用于测试的原始小数: 0.05477
我之前参考的代码算出来的结果: 0.0548
我改进我参考的代码算出来的结果: 0.05477

# ——————————————————

再试试 x=1.05477
输出结果↓
用于测试的原始小数: 1.05477
我之前参考的代码算出来的结果: 1.05
我改进我参考的代码算出来的结果: 1.055

# ——————————————————

再试试 x=123.05477
输出结果↓
用于测试的原始小数: 123.05477
我之前参考的代码算出来的结果: 123
我改进我参考的代码算出来的结果: 123.055

# ——————————————————

再试试 x=100.05477
输出结果↓
用于测试的原始小数: 100.05477
我之前参考的代码算出来的结果: 100
我改进我参考的代码算出来的结果: 100.055

# ——————————————————

再试试 x=2.05477
输出结果↓
用于测试的原始小数: 2.05477
我之前参考的代码算出来的结果: 2.05
我改进我参考的代码算出来的结果: 2.055

# ——————————————————

再试试 x=2.00007
输出结果↓
用于测试的原始小数: 2.00007
我之前参考的代码算出来的结果: 2.00
我改进我参考的代码算出来的结果: 2.000

# ——————————————————

再试试 x=2.01007
输出结果↓
用于测试的原始小数: 2.01007
我之前参考的代码算出来的结果: 2.01
我改进我参考的代码算出来的结果: 2.010

# ——————————————————

再试试 x=2.00107
输出结果↓
用于测试的原始小数: 2.00107
我之前参考的代码算出来的结果: 2.00
我改进我参考的代码算出来的结果: 2.001

# ——————————————————

再试试 x=2.00607
输出结果↓
用于测试的原始小数: 2.00607
我之前参考的代码算出来的结果: 2.01
我改进我参考的代码算出来的结果: 2.006

# ——————————————————

再试试 x=0.00667
输出结果↓
用于测试的原始小数: 0.00667
我之前参考的代码算出来的结果: 0.00667
我改进我参考的代码算出来的结果: 0.00667



################################################################

我要的最终目的是写1个函数,强制的、正确四舍五入的、保留3位小数。
如果你给1个小数,比如100.00153要求保留3位小数。
那就正确的四舍五入,给3位小数,100.002

但是,经过我的测试,。大约1的小数都正常得出结果。
但是小于1的小数,就失效了。
————————————————————

#######################网站上再次找到的文章#########################################
参考链接:https://blog.csdn.net/haeasringnar/article/details/105471581
# ——————————————
# 使用decimal 和 getcontext 提高精度
from decimal import Decimal, getcontext
print('未指定精度')
print(Decimal(0.1) + Decimal(0.2)) # 发现使用decimal 计算时,小数后面计算的更加的精确
print(Decimal(1.234) + Decimal(1.2))

print('指定精度')
getcontext().prec = 4 # 指定精度,包含非零整数部分
print(Decimal(0.1) + Decimal(0.2)) # 再次输出,小数精度会发生改变。值得注意的是,它不会抹除0
print(Decimal(1.234) + Decimal(1.2))
————————————————

# 使用round 提高精度
# 语法 round(val, num) 参数为传入的数据和指定的小数点位数
print(round(0.1 + 0.2, 3)) # 指定小数点保留的位数,当最右边存在0时,自动抹除,进位采用四舍五入
print(round(1.234, 2))
print(round(1.235, 2))

############## round 函数也存在精度丢失问题 ↓############################
参考文章:https://blog.csdn.net/u013946150/article/details/116194440
问题 

一般的四舍五入操作都是使用内置的round方法,但有时候会出现问题。比如

In [1]: round(2.675,2)

Out[2]: 2.67

 

为什么不是2.68呢?那是因为float精度缺失导致的。

In [3]: Decimal(2.675)

Out[4]: Decimal('2.67499999999999982236431605997495353221893310546875')

 

你会发现,2.675其实是2.6749999999…,四舍五入可不是2.67么?那这个问题怎么解决呢?

方法 

可以使用str.format来格式化数字实现四舍五入

from decimal import Decimal

In [4]: '{:.2f}'.format(Decimal('2.675'))

Out[5]: '2.68'

############## round 函数也存在精度丢失问题 ↑############################

############## 当我换成保留3位小数时,问题依旧 ↓############################

上面这个方法依然不行,比如我要保留3位小数
源码如下:
from decimal import Decimal
x=1.0545
# 原先参考的代码
y= '{:.3f}'.format(Decimal(str(x)))
print(y)
print(y,"的输出结果的数据类型:",type(y))
print("试试再转成浮点数:",float(y))
# ————————
输出结果:
1.054
1.054 的输出结果的数据类型: <class 'str'>
试试再转成浮点数: 1.054

菜鸟IT博客[2021.10.16-19:56] 访问:2068
[关闭窗口]  
Google公司(谷歌联盟)提供的广告↓
本页的htm伪静态链接网址:分享链接加载中....

收藏链接: www.ems-help.com | www.17post.com | www.17track.wang | www.kd100.wang | www.17wx.net | www.11185cha.com | www.sftrack.net | www.kdjiage.com | m.kdjiage.com | www.expba.net | m.expba.net | www.pptrack.net
学习Python的关键点
【1】★ Python:解决小数点后面四舍五入的精度丢失问题(二进制转换导致,另解决prec动态保留小数点后多少位)
【2】 ★ Python:单个py文件打包exe程序
【3】 ★ 给自己写的exe程序加上注册授权保护
【4】 ★ Python的http请求超时设置(timeout)| 异常类型/捕获异常
【5】 ★ Python的多线程的线程池的使用| ThreadPoolExecutor
【6】 ★ Python能用到的免费代理IP网址
【7】 ★ Python_用于测试代理IP是否有效
【8】 ★ Python Requests post() 方法 | post方式提交api
【9】 ★★★ Python Tkinter Gui视频学习教程
【10】 ★★★ Python 小项目实战-视频学习教程
【11】 ★★★ Python 爬虫项目实战-视频教程
【12】 ★★★ 高级进阶的关于python的五本书: 「Python从菜鸟到高手」、「html5+css3+JavaScript从入门到精通」、「Django Web应用开发实战」、「漫画算法」
【13】 ★★★ Request库-爬虫
【14】 ★★★ Python 图形识别文字
【15】 ★★★ Python 滑动验证码识别【图文教程】
【16】 ★★★ Python 滑动验证码识别【视频教程】
【18】 ★★★ Python 关于Class类的应用【视频教程】
【19.1】 ★★★ Python 关于进度条的制作(1)
【19.2】 ★★★ Python 关于进度条的制作(2)
【20】★★★ Python 抓取某宝的商品信息
【21】★★★ Python 一小时学会全栈开发浏览器版本的企业管理系统【视频教程】
【22】★★★ Python 全栈开发——前端+后端【视频教程】
【23】★★★ Layui 浏览器前端模块化UI框架
【24】★★★ Python-Django-Web应用开发【视频教程】
【25】★★★ Python 从0开始学【视频教程】
【26】★★★ Python的tkinter界面打包exe以后关于icon图标报错的解决办法!
【27】★★★ Python的tkinter视频学习教程【N个系统性学习合集视频】★★★
【28】★★★ Python全栈开发【视频教程】★★★
Copyright © 17WX.NET 版权所有 Manage 沪ICP备13006304号-5 沪公网安备31011702006630号
,sitemap.html,sitemap.xml
网站人气值: