`
thihy
  • 浏览: 69659 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

【讨论】为啥0.2+0.4 != 0.6(浮点数计算的精度问题)

 
阅读更多
网上有很多帖子讨论浮点数的精度问题,其中有如下命题:
  1. 0.2+0.4=0.600 000 000 000 000 1
  2. 0.58*10=5.8,但0.58*100=57.999 999 999 999 990.58*1000=580
 
首先,我们可以肯定的是:浮点数是不能完全表示实数集的(从信息论的角度很容易得出此结论),所以必然存在误差。
而对有误差的数据进行计算,会带来累加误差
 
这里讨论的都是二进制格式的浮点数表示,不包括十进制等其他进制的表示。
 

浮点数表示的误差

 

先简单介绍一下浮点数表示。大家不必自己计算,可以去http://babbage.cs.qc.cuny.edu/IEEE-754/http://babbage.cs.qc.cuny.edu/IEEE-754.old/Decimal.html。后者可以看到实际的值。
 
在IEEE标准中,浮点数用三元组 < 符号位s, 指数e, 有效数字t> 来表示 (-1)s×t×2e
 

整数的表示

 

对于十进制的整数,如果有效数字不太多,则是可以精确表示的。比如100 表示为(-1)0×1.1001×26
 

但是如果有效数字太多,则可能会出问题。比如对于12 345 678 901 234 567 000,即使使用了double(binary64)来表示,结果为1.010 101 101 010 100 101 010 011 000 110 011 101 011 000 111 110 000 1×263,但这个二进制表示其实代表的却是1.234 567 890 123 456 7e19。

 

小数0.6如何表示?

 

对于整数,二进制表示只会丢失有效数字,而不会有其他的编号。然而对于小数,则可能会很麻烦,因为小数的二进制表示可能是无限循环的。

 

比如,对于0.6,的binary64表示:

(0.6)10 = (0.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 1...)2

            = (1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001...)2×2-1

 

于是,符号位s=0,指数e为-1,有效数字为1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001...

 

我们知道,binary64的有效数字最多有53位,也就是说

1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001... 的黄色部分需要被抛弃。

 

那么我们应该如何抛弃这部分数据呢?在IEEE中规定了若干舍入方法,一般来说,普遍使用的是roundTiesToEven方式来舍入。

 

roundTiesToEven方法:round到相邻的浮点数据上。如果两个浮点数据都一样近,
则round到最后一位是偶数的浮点数据上。

 

由此,0.6~=(-1)0×1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 1×2-1

 

再试试0.2和0.4

(0.2)10 =(0.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 1...)2

            =(1.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 1...)2×2-3 。

(0.4)10 =(0.011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 0...)2

            =(1.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 10...)2×2-2

 

使用roundTiesToEven方式舍入黄色部分后,前面的部分加1。也即

 

0.2 =(1.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 101 0)2×2-3

0.4 =(1.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 101 0)2×2-2

 

其实,0.2和0.4的有效位数是一样的,只是指数不同。

 

到现在,我们可以发现。0.2和0.4都是向上取整的,也即浮点数表示的值比实际值是要大那么一丢丢的。

浮点数计算误差

浮点数在计算时也是有误差的。
比如对于0.2+0.4,0.2对应的指数是-3, 0.4对应的指数是-2。IEEE要求结果应该优先使用-3作为指数(也即较小的指数值)

当采用-3作为指数时,0.2和0.4需要表示成

 

0.2 =(  1.100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 101 0)2×2-3

0.4 =(11.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 010   )2×2-3

 

可以看到,小数位后,0.4少了一位,我们需要用0补齐,然后计算加法。得到

 

0.2+0.4=(100.110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 100 111 0×2-3)2

 

规则化

 

0.2+0.4=(1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 001 110)2×2-1

 

我们又需要舍弃黄色部分了,在这里,由于它离两边是一样近的,于是我们round到最后一位是偶数的浮点数上,于是有

 

0.2+0.4=(1.001 100 110 011 001 100 110 011 001 100 110 011 001 100 110 011 010 0__)2×2-1

 

请注意:这里我们又往上取整了,也即此处的结果是比实际值要大那么一丢丢的。

 

而这个结果到底是多少呢?精确结果是0.600 000 000 000 000 088 817 841 970 012 523 233 890 533 447 265 625

考虑到有效数字,小数点后只保留16位,所以需要舍弃黄色部分,其结果是0.600 000 000 000 000 1=0.600 000 000 000 000 0 + 1E-16。

 

0.2+0.4的最后那个1来自哪里?

  1. 对0.2舍入时,我们偏大了一丢丢。>=1.5 × 2-57
  2. 对0.4舍入时,我们偏大了一丢丢。>=1.5 × 2-56
  3. 对0.2+0.4舍入时,我们偏大了一丢丢。= 1 × 2-54
  4. 在输出时,我们又偏大了一丢丢。
哈,我们连续三次偏大了一丢丢,也是偏大发了,就多出了哪个1来了。总共偏差>=(1.5 + 1.5 × 2 + 1 × 2×2×2) * 2-57 = 1.5625 × 2-54 >8.6e-17。考虑到在输出因为四舍五入,从而会多出最后的那个1。
 

最后的总结

  1. 浮点数表示可能存在Round
  2. 浮点数计算可能存在Round
  3. 结果输出时可能存在Round
这些Round的累加可能会引起有效数字的最后一位偏大或偏小。
题外:对于0.2或0.4,如果采用其他的Round方法,则有可能0.2+0.4=0.6的。而具体采用何种Round,是由语言实现平台决定,或者程序指定的。
8
2
分享到:
评论
10 楼 thihy 2013-05-15  
jellyfish 写道

    浮点数表示可能存在Round
    浮点数计算可能存在Round
    结果输出时可能存在Round


The error bound is Math.ulp(), assuming operations are +/-/*//. So we are safe most of the time.

However, when dealing with Math.exp(), we are in big trouble for large numbers.


哈,刚发现Math下面还有这个方法 ,3ks。
9 楼 thihy 2013-05-15  
justjavac 写道
chenjinbo1983 写道
用BigDecimal不就可以了

BigDecimal确实可以精确表示数,但是在计算数时,也无能为力。所以,还是有必要了解一下IEEE754,昨天把那个工具汉化了一下,http://justjavac.com/tools/ieee-754-floating-point-conversion-from-floating-point-to-hexadecimal.html

赞。但是原来的页面有一个不好的地方,“有效数字”的部分的Input有些短,总看不到后面的部分。要是能长一些就好了。
8 楼 justjavac 2013-05-15  
chenjinbo1983 写道
用BigDecimal不就可以了

BigDecimal确实可以精确表示数,但是在计算数时,也无能为力。所以,还是有必要了解一下IEEE754,昨天把那个工具汉化了一下,http://justjavac.com/tools/ieee-754-floating-point-conversion-from-floating-point-to-hexadecimal.html
7 楼 justjavac 2013-05-15  
thihy 写道
chenjinbo1983 写道
用BigDecimal不就可以了

实际使用时,如果对结果要求不是完整精确的,没有必要使用BigDecimal。而对于某些无理数,BigDecimal也无济于事。

这里主要是指明浮点数存在误差,所以在对浮点数进行操作时,要小心。不要潜意识地认为它是“精确的”。

对。BigDecimal不是终极解决办法,否则就没有必要使用浮点数了。BigDecimal是用定点数表示数字,所以,在范围是是有限的。
6 楼 jellyfish 2013-05-14  

    浮点数表示可能存在Round
    浮点数计算可能存在Round
    结果输出时可能存在Round


The error bound is Math.ulp(), assuming operations are +/-/*//. So we are safe most of the time.

However, when dealing with Math.exp(), we are in big trouble for large numbers.
5 楼 thihy 2013-05-14  
chenjinbo1983 写道
用BigDecimal不就可以了

实际使用时,如果对结果要求不是完整精确的,没有必要使用BigDecimal。而对于某些无理数,BigDecimal也无济于事。

这里主要是指明浮点数存在误差,所以在对浮点数进行操作时,要小心。不要潜意识地认为它是“精确的”。
4 楼 chenjinbo1983 2013-05-14  
用BigDecimal不就可以了
3 楼 thihy 2013-05-13  
justjavac 写道
提点建议,<符号位s, 指数e, 有效数字t> 这行字加粗了。

我觉得,应该把文章中有用的,或者知识点加粗。那么长的010101串,最好按4位或者8位分隔开,这样容易看。

对于大串的0101,你在后面不一样的地方加黄色背景,很赞。希望其它的不利于阅读,不利于理解的格式也调整一下。让文章锦上添花。


这格式粘贴的。感觉HTML编辑器就是不如Word爽。有时间搞定一下。
2 楼 justjavac 2013-05-13  
提点建议,<符号位s, 指数e, 有效数字t> 这行字加粗了。

我觉得,应该把文章中有用的,或者知识点加粗。那么长的010101串,最好按4位或者8位分隔开,这样容易看。

对于大串的0101,你在后面不一样的地方加黄色背景,很赞。希望其它的不利于阅读,不利于理解的格式也调整一下。让文章锦上添花。
1 楼 justjavac 2013-05-13  
赞一个,比我写的详细。

相关推荐

    隐马尔科夫算法(HMM)的Java实现

    - 考虑到浮点数运算的精度问题,在计算概率时采用对数概率。 - 在实际应用中,还需要实现具体的算法来完成如预测、解码等功能。 #### 结论 通过上述分析,我们可以看到Java实现的HMM类是如何组织和封装关键信息...

    Aviator-2.3.0用户指南

    - **2013-05-18**: 完成0.6版本更新,新增了对大数和精度计算的支持,以适配Aviator 2.3.0版本。 - **2010-06-28**: 发布0.1版本。 - **2010-09-07**: 修改并完成0.2版本。 - **2011-07-13**: 完成0.3版本,适配...

    基于AT89S52 单片的频率计

    一般选择C3 为0.1uF 的独石电容,R1 为1K 的电阻,正脉冲有效宽度为: ln10*R1*C3=230&gt;2,即可以该电路可以产生有效复位。 ( 3 ) 程序下载线接口: AT89S52 自带有isp 功能,ISP 的全名为In System Programming,即...

    deepseek经验分享-陈雄.pptx

    deepseek经验分享-陈雄.pptx

    采用springboot框架的基于Java的家政服务平台的设计与实现(Java项目编程实战+完整源码+毕设文档+sql文件+学习练手好项目).zip

    本家政服务平台就是在这样的大环境下诞生,其可以帮助管理者在短时间内处理完毕庞大的数据信息,使用这种软件工具可以帮助管理人员提高事务处理效率,达到事半功倍的效果。此家政服务平台利用当下成熟完善的Spring Boot框架,使用跨平台的可开发大型商业网站的Java语言,以及最受欢迎的RDBMS应用软件之一的MySQL数据库进行程序开发。家政服务平台有管理员,雇主,雇员三个角色。管理员功能有个人中心,雇主管理,雇员管理,资料认证管理,项目类型管理,服务项目管理,需求信息管理,服务预约管理,申请预约管理,签订合同管理,雇主评价管理,留言板管理,系统管理。雇主可以发布需求,雇员可以申请预约,雇主支付报酬,雇主和雇员可以签订合同,雇主可以对雇员进行评价。家政服务平台的开发根据操作人员需要设计的界面简洁美观,在功能模块布局上跟同类型网站保持一致,程序在实现基本要求功能时,也为数据信息面临的安全问题提供了一些实用的解决方案。可以说该程序在帮助管理者高效率地处理工作事务的同时,也实现了数据信息的整体化,规范化与自动化。 关键词:家政服务平台;Spring Boot框架;MySQL;自动化

    SAP SD-Class 4 Item proposal &amp; CMIR-Customer material info record.mp4

    SAP SD-Class 4 Item proposal & CMIR-Customer material info record.mp4

    【毕业设计】“跑鸭”微信小程序-一款基于校园跑步的社交小程序【源码+论文+答辩ppt+开题报告+任务书】.zip

    【毕业设计】“跑鸭”微信小程序-一款基于校园跑步的社交小程序(实时里程配速、运动路径、整公里提醒、周榜月榜、打卡分享、热门推荐、线上活动、勋章墙、隐私设置 【源码+论文+答辩ppt+开题报告+任务书】.zip【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

    大学生创新创业大赛项目 - 仿 Envato 的电商项目.zip

    大学生创业项目源码

    Python爬虫实例,一个简单的DEMO

    使用requests和BeautifulSoup库爬取豆瓣电影Top250的基本信息

    电动汽车(EV)保有量数据集(232K+记录,17特征)CSV

    数据集文件包含美国各地电动汽车 (EV) 注册的详细记录,其结构便于分析并与数据处理工具集成。它通常以 CSV 格式提供,以确保与各种数据分析平台的兼容性。 关键列和数据属性: 做:电动汽车制造商(例如,特斯拉、日产、雪佛兰)。 型:车辆的特定型号(例如,Model S、Leaf、Bolt)。 车型年份:车辆模型的制造年份。 电动续航里程:每次充电的估计电动行驶里程(以英里为单位)。 EV 类型:将车辆分类为电池电动汽车 (BEV) 或插电式混合动力电动汽车 (PHEV)。 州和县:车辆注册的地理位置,允许进行区域分布分析。 注册人数:每个地区每个车型注册的车辆数量,有助于识别高浓度的 EV 区域。

    施耐德ATV312变频器通过MCGS RTU通讯实现双机监控与控制的触摸屏集成解决方案,无PLC的施耐德ATV312变频器通讯示例:触摸屏控制监控两台变频器,功能多且省成本,改进型可调整步长 P&O

    施耐德ATV312变频器通过MCGS RTU通讯实现双机监控与控制的触摸屏集成解决方案,无PLC的施耐德ATV312变频器通讯示例:触摸屏控制监控两台变频器,功能多且省成本,改进型可调整步长 P&O MPPT(二区MPPT复现),光储系统MPPT 直流负载供电的单级离网光伏系统中,降压转器将太阳能光伏阵列和直流负载连接起来,同时确保最大功率点跟踪(MPPT) 和电池充电控制的良好运行。 在MPPT方面,提出了一种改进的自适应步长扰动观测(P&O)方法,以达到不同天气条件下太阳能光伏阵列的实际最大功率点(MPP),同时减少稳态振荡和功率损耗。 此外,电池充电控制侧使用三级充电控制器 (TSCC) 为铅酸电池站充电。 ,改进型P&O; 复现二区MPPT; 光储系统MPPT; 最大功率点跟踪(MPPT); 步长扰动观测; 降压转换器; 太阳能光伏阵列; 电池充电控制; 三级充电控制器(TSCC); 铅酸电池站。,改进型P&O MPPT技术,光储系统高效能量管理

    基于stm32家庭安全防控系统 (程序+WiFi)

    基于stm32家庭安全防控系统 (程序+WiFi)

    Maxwell电机与Simplorer联合仿真教程:矢量控制SVPWM算法与电路搭建详解,自定义电机模型替换指南,Maxwell电机与Simplorer联合仿真教程:电路搭建及矢量控制SVPWM算法实

    Maxwell电机与Simplorer联合仿真教程:矢量控制SVPWM算法与电路搭建详解,自定义电机模型替换指南,Maxwell电机与Simplorer联合仿真教程:电路搭建及矢量控制SVPWM算法实

    CNN-master.zip

    CNN相关以及垃圾分类数据集

    基于springboot框架的流浪动物救助网站的设计与实现(Java项目编程实战+完整源码+毕设文档+sql文件+学习练手好项目).zip

    互联网发展至今,无论是其理论还是技术都已经成熟,而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播,搭配信息管理工具可以很好地为人们提供服务。针对信息管理混乱,出错率高,信息安全性差,劳动强度大,费时费力等问题,采用流浪动物救助网站可以有效管理,使信息管理能够更加科学和规范。 流浪动物救助网站在Eclipse环境中,使用Java语言进行编码,使用Mysql创建数据表保存本系统产生的数据。系统可以提供信息显示和相应服务,其管理员增删改查动物信息和动物信息资料,审核动物信息预订订单,查看订单评价和评分,通过留言功能回复用户提问。 总之,流浪动物救助网站集中管理信息,有着保密性强,效率高,存储空间大,成本低等诸多优点。它可以降低信息管理成本,实现信息管理计算机化。 关键词:流浪动物救助网站;Java语言;Mysql

    采用springboot框架的基于web的机动车号牌管理系统的设计与实现(Java项目编程实战+完整源码+毕设文档+sql文件+学习练手好项目).zip

    对机动车号牌信息管理的提升,也为了对机动车号牌信息进行更好的维护,机动车号牌管理系统的出现就变得水到渠成不可缺少。通过对机动车号牌管理系统的开发,不仅仅可以学以致用,让学到的知识变成成果出现,也强化了知识记忆,扩大了知识储备,是提升自我的一种很好的方法。通过具体的开发,对整个软件开发的过程熟练掌握,不论是前期的设计,还是后续的编码测试,都有了很深刻的认知。 机动车号牌管理系统通过MySQL数据库与Spring Boot框架进行开发,机动车号牌管理系统能够实现牌照换补申请管理,用户管理,牌照申请管理,牌照转移申请管理,车辆信息管理,公告信息管理等功能。 通过机动车号牌管理系统对相关信息的处理,让信息处理变的更加的系统,更加的规范,这是一个必然的结果。已经处理好的信息,不管是用来查找,还是分析,在效率上都会成倍的提高,让计算机变得更加符合生产需要,变成人们不可缺少的一种信息处理工具,实现了绿色办公,节省社会资源,为环境保护也做了力所能及的贡献。 关键字:机动车号牌管理系统,牌照,车辆信息

    Maxwell电机与Simplorer联合仿真教程:矢量控制SVPWM算法及电路搭建指南,包含详细视频与可复制电机模型替换示范,教程Simplorer与Maxwell电机联合仿真,详细教程包含电路

    Maxwell电机与Simplorer联合仿真教程:矢量控制SVPWM算法及电路搭建指南,包含详细视频与可复制电机模型替换示范,教程Simplorer与Maxwell电机联合仿真,详细教程包含电路

    Python实现基于IBES-ELM基于改进的秃鹰搜索优化算法优化极限学习机的数据回归预测 多指标的详细项目实例(含完整的程序,GUI设计和代码详解)

    内容概要:本文档详细介绍了一个名为《Python实现基于IBES-ELM基于改进的秃鹰搜索优化算法优化极限学习机的数据回归预测》的项目。该项目旨在通过结合改进的秃鹰搜索优化算法(IBES-EO)和极限学习机(ELM),优化ELM模型以提高其预测精度,尤其针对多指标、高维数据以及噪声数据的处理进行了探讨。项目涵盖了从数据预处理到建模预测的一系列完整流程,并提供了代码案例和GUI界面设计思路。文档详细阐述了模型的工作机制、适用场景及其实现细节。 适合人群:对机器学习有兴趣,特别是对ELM、IBES-EO感兴趣的研究人员、开发人员和技术爱好者。 使用场景及目标:适用于各种回归预测问题,包括但不限于金融预测、气象预测、健康数据分析和智能交通系统等。目标在于提供一种高效的解决方案,提高在大规模复杂数据集中进行回归预测的能力,同时也展示了如何将生物启发式的优化算法运用于改进现有的机器学习模型,为实际应用提供更多可能。 阅读建议:文档按照章节顺序编排,从背景介绍到具体实现再到最终总结。初学者可以从头至尾通读,以掌握全流程概念和技能;有一定经验的读者可以直接跳转至自己感兴趣的环节,例如优化算法的具体设计或者代码实现部分。建议边学习边动手实验,以达到最佳的学习效果,并可通过提供的完整示例代码加深理解和记忆。此外,项目中有关于系统架构设计、API接口搭建等内容也可作为实际工程项目参考。

    AdaBoost分类算法案例

    本案例使用鸢尾花萼长度(sepal length)、花萼宽度(sepal width)、花瓣长度(petal length)和花瓣宽度(petal width)作为特征,采用Adaboost算法将其进行分类。 同学们通过本案例学习Adaboost算法的理论基础以及在分类问题中的应用,同时通过实际操作加深对分类算法和数据分析的理解。更好的掌握机器学习算法,培养对数据科学的兴趣和实践能力。

    【毕业设计】基于微信小程序的农产品扶贫助农系统【源码+论文+答辩ppt+开题报告+任务书】.zip

    【项目资源】:包含前端、后端、移动开发、操作系统、人工智能、物联网、信息化管理、数据库、硬件开发、大数据、课程资源、音视频、网站开发等各种技术项目的源码。包括STM32、ESP8266、PHP、QT、Linux、iOS、C++、Java、MATLAB、python、web、C#、EDA、proteus、RTOS等项目的源码。 【项目质量】:所有源码都经过严格测试,可以直接运行。功能在确认正常工作后才上传。 【适用人群】:适用于希望学习不同技术领域的小白或进阶学习者。可作为毕设项目、课程设计、大作业、工程实训或初期项目立项。 【附加价值】:项目具有较高的学习借鉴价值,也可直接拿来修改复刻。对于有一定基础或热衷于研究的人来说,可以在这些基础代码上进行修改和扩展,实现其他功能。 【沟通交流】:有任何使用上的问题,欢迎随时与博主沟通,博主会及时解答。鼓励下载和使用,并欢迎大家互相学习,共同进步。

Global site tag (gtag.js) - Google Analytics