网上有很多帖子讨论浮点数的精度问题,其中有如下命题:
-
0.2+0.4=0.600 000 000 000 000 1
-
0.58*10=5.8
,但0.58*100=57.999 999 999 999 99
,0.58*1000=580
首先,我们可以肯定的是:浮点数是不能完全表示实数集的(从信息论的角度很容易得出此结论),所以必然存在误差。
而对有误差的数据进行计算,会带来累加误差。
这里讨论的都是二进制格式的浮点数表示,不包括十进制等其他进制的表示。
浮点数表示的误差
在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来自哪里?
- 对0.2舍入时,我们偏大了一丢丢。>=1.5 × 2-57
- 对0.4舍入时,我们偏大了一丢丢。>=1.5 × 2-56
- 对0.2+0.4舍入时,我们偏大了一丢丢。= 1 × 2-54
- 在输出时,我们又偏大了一丢丢。
哈,我们连续三次偏大了一丢丢,也是偏大发了,就多出了哪个1来了。总共偏差>=(1.5 + 1.5 × 2 + 1 × 2×2×2) * 2-57 = 1.5625 × 2-54 >8.6e-17。考虑到在输出因为四舍五入,从而会多出最后的那个1。
最后的总结
- 浮点数表示可能存在Round
- 浮点数计算可能存在Round
- 结果输出时可能存在Round
这些Round的累加可能会引起有效数字的最后一位偏大或偏小。
题外:对于0.2或0.4,如果采用其他的Round方法,则有可能0.2+0.4=0.6的。而具体采用何种Round,是由语言实现平台决定,或者程序指定的。
分享到:
相关推荐
- 考虑到浮点数运算的精度问题,在计算概率时采用对数概率。 - 在实际应用中,还需要实现具体的算法来完成如预测、解码等功能。 #### 结论 通过上述分析,我们可以看到Java实现的HMM类是如何组织和封装关键信息...
- **2013-05-18**: 完成0.6版本更新,新增了对大数和精度计算的支持,以适配Aviator 2.3.0版本。 - **2010-06-28**: 发布0.1版本。 - **2010-09-07**: 修改并完成0.2版本。 - **2011-07-13**: 完成0.3版本,适配...
一般选择C3 为0.1uF 的独石电容,R1 为1K 的电阻,正脉冲有效宽度为: ln10*R1*C3=230>2,即可以该电路可以产生有效复位。 ( 3 ) 程序下载线接口: AT89S52 自带有isp 功能,ISP 的全名为In System Programming,即...
辣椒油树脂检验表格(食品添加剂食用香精质量验收记录表).docx
字体路径文件
Screenshot_2025-03-14-16-46-14-26.jpg
交警队伍管理制度.docx
乳酸链球菌素检验表格(食品添加剂食用香精质量验收记录表).docx
编译的axel windows工具,有需要的拿去 使用命令例子如下 cmd 界面下cd 到axel.exe 文件路径 比如下载image net 1k axel -n 8 -o ./ https://image-net.org/data/ILSVRC/2012/ILSVRC2012_img_train.tar --insecure 编译过程的记录为 https://blog.csdn.net/Magicapprentice/article/details/146250906?sharetype=blogdetail&sharerId=146250906&sharerefer=PC&sharesource=Magicapprentice&spm=1011.2480.3001.8118 可以参照这个链接从零开始自己编译
羧甲基淀粉钠检验表格(食品添加剂食用香精质量验收记录表).docx
光学多层膜系统模拟仿真matlab代码 这段代码是一个光学多层膜系统的模拟程序,计算了TE模和TM模的反射率,并绘制了反射率随波长和入射角变化的等高线图。 这里是代码的主要流程: 1. 加载材料参数数据(Al2O3、Si3N4、SiO2、Ag)和波长数据(lambda)。 2. 循环遍历不同的入射角度(theta0)。 3. 对于每个入射角度,计算TE模和TM模的传输矩阵,包括各个层的传输矩阵。 4. 计算反射率,并将TE模和TM模的反射率取平均作为总的反射率。 5. 将总的反射率随波长和入射角度的变化绘制成等高线图。 这段代码非常详细,而且注释也很清晰,让人容易理解。 不过最后一行的中文注释应该是解释如何使用`colormap`函数来设置绘图的颜色映射,可以将其翻译为“设置颜色映射为Jet色彩”。 ,多层膜系统模拟; TE模和TM模反射率计算; 波长和入射角变化; 传输矩阵; 平均反射率; 绘制等高线图; 颜色映射设置。,光学多层膜系统模拟仿真:Matlab代码实现
中国城市统计年鉴全集(1985-2022).zip。内容来源于网络分享,如有侵权请联系我删除。
双向DC DC全钒液流蓄电池充放电储能matlab simulink仿真模型,采用双闭环控制,充放电电流和电压均可控,直流母线端电压可控,电流为负则充电,电流为正则放电,可以控制电流实现充放电 (1)完整复现文献全钒液流模型,多个全钒液流电池串联成电池组,提供模型参数,电压等级可调 (2)可通过电流环控制电池充放电电流,可实现不同充放电电流,控制速度快(电流闭环) (3)可通过电压环控制电池两端充放电电压,可实现不同充放电电流,控制速度快(电压闭环) ,全钒液流电池; 双向DC-DC; 充放电控制; 电流环控制; 电压环控制; MATLAB Simulink仿真模型; 电池组; 模型参数; 电压等级可调; 电流闭环; 电压闭环,Matlab Simulink仿真模型:全钒液流电池双闭环充放电控制储能系统
windows平台mysql版本安装包 mysql-installer-community
分享课程——BEV模型部署全栈教程(3D检测+车道线+Occ)课程
基于FPGA流水线结构并行FFT的设计与实现-王英喆.caj
内核驱动开发,调试监控IRP请求包发送接收工具
comsol三元锂离子电池模型 NCA111三元锂离子电池21700 电化学-热耦合模型 老化模型 容量衰减模型 参数已经设置好 自己更改参数即可进行使用学习 可进行多倍率充放电仿真 有对应参考文献 A17 ,comsol模型;三元锂离子电池;NCA111电池;电化学-热耦合模型;老化模型;容量衰减模型;参数设置;仿真学习;参考文献,COMSOL三元锂离子电池模型与NCA111电池仿真研究
野火征途Pro FPGA开发板 实现基于帧差法的运动目标检测与跟踪 摄像头:OV5640 显示屏:TFT LCD,VGA,HDMI ,野火征途Pro; FPGA开发板; 帧差法; 运动目标检测与跟踪; OV5640摄像头; TFT LCD; VGA; HDMI,野火征途Pro FPGA开发板:运动目标检测与跟踪的视觉处理