valid floating point value什么意思_为什么 0.1 + 0.2 = 0.300000004?

往期热门文章:

1、往期精选优秀博文都在这里了!2、求求你!数据库不要再使用外键了?3、还在写慢SQL?4、ELK太笨重了?想放弃?快试试日志系统新贵Loki吧!5、谁再悄咪咪的吃掉异常,我上去就是一 JIO

JavaScript 作为一门诞生自上个世纪 90 年代的编程语言,从诞生之初就因为诡异的隐式类型转换等原因被黑,很多 JavaScript 的开发者还会吐槽浮点数加法的『奇葩』问题 — 为什么 0.1 + 0.2 在 JavaScript 中不等于 0.3,相信很多人都对这个问题的答案有一个大概的认识,但是都没有深入研究过,这个问题的答案让 William Kahan 在 1989 年获得图灵奖

> 0.1 + 0.20.30000000000000004

其实有上述问题的不止 JavaScript 一门编程语言,几乎所有现代的编程语言都会遇到上述问题,包括 Java、Ruby、Python、Swift 和 Go 等等,你可以在 https://0.30000000000000004.com/ 中找到常见的编程语言在计算上述表达式的结果。这不是因为它们在计算时出现了错误,而是因为浮点数计算标准的要求。

125de22be9658caedc1a735d800a6250.png
floating-point-math

图 1 - 常见的浮点数『错误』

从最开始接触 C 语言编程,作者就接触到了浮点数 float,然而在很长一段时间中,作者都将编程中的浮点数和数学中的小数看做同一个东西,不过当我们重新审视它们时,会发现这两个概念的不同之处。

  • 编程中的浮点数的精度往往都是有限的,单精度的浮点数使用 32 位表示,而双精度的浮点数使用 64 位表示;
  • 数学中的小数系统可以通过引入无限序列 ... 可以任意的实数;

在数学上我们总有办法通过额外的符号表示更复杂的数字,但是从工程的角度来看,表示无限精度的数字是不经济的,我们期望通过更小和更快的系统表示范围更大和精度更高的实数。浮点数系统是在工程上面做的权衡,IEEE 754 就是在 1985 年建立的浮点数计算标准,它定义了浮点数的算术格式、交换格式、舍入规则、操作和异常处理。讨论浮点数也无法脱离该标准,为了回答今天的问题,我们将从以下的两个角度触发:

  • 二进制无法在有限的长度中精确地表示十进制中 0.1 和 0.2;
  • 单精度浮点数、双精度浮点数的位数决定了它们能够表示的精度上限;

二进制与十进制

我们日常生活中使用的数字基本都是 10 进制的,然而计算机使用二进制的 0 和 1 表示整数和小数,所有有限的十进制整数都可以无损的转换成有限长度的二进制数字,但是要在二进制的计算机中表示十进制的小数相对就很麻烦了,我们以 0.375 为例介绍它在二进制下的表示:

小数点后面的位数依次表示十进制中的 0.5、0.25、0.125 和 0.0625 等等,这个表示方法非常好理解,每一位都是前一位的一半。0.375 在二进制表示看来确实是『整数』。然而如下图所示,想要使用二进制表示十进制中的 0.1 和 0.2 是比较复杂的:

2a200f427ae5029ad27a2f05faac68cc.png
decimals-binary-representation

图 2 - 二进制表示的十进制小数

无论是 0.1 还是 0.2,这两个数字都不是二进制中的『整数』,我们没有办法精确地表示它们,只能通过无限循环小数尝试接近它们的真实值;与之相似的是,它们相加的结果 0.3 也无法用有限长度的二进制表示:

568a3367cf0705655d6dee67a0e6bb4b.png
dot-three-binary-representation

图 3 - 二进制表示的 0.3

这三个不同的数字都会在最后的小数部分无限循环 1100 来趋近于真实值,如果计算机中的浮点数可以表示无限循环小数就有可能解决这个问题,但是事实的真相是浮点数只会表示有限小数,所有超过特定精度的数字都会做舍入处理。

精度上限

编程语言中的浮点数一般都是 32 位的单精度浮点数 float 和 64 位的双精度浮点数 double,部分语言会使用 float32 或者 float64 区分这两种不同精度的浮点数。想要使用有限的位数表示全部的实数是不可能的,不用说无限长度的小数和无理数,因为长度的限制,有限小数在浮点数中都无法精确的表示。

6570a453e2590a947a19493556796dd6.png
float-and-double

图 4 - 单精度与双精度浮点数

  • 单精度浮点数 float 总共包含 32 位,其中 1 位表示符号、8 位表示指数,最后 23 位表示小数;
  • 双精度浮点数 double 总共包含 64 位,其中 1 位表示符号,11 位表示指数,最后 52 位表示小数;

我们以单精度浮点数 0.15625 为例,介绍该浮点数在计算机二进制中的表示方法,如下图所示,符号位 0 表示该浮点数为正数,中间的 8 位指数总共可以表示 256 个数字,其中从 [0, 126] 表示 [-127, -1],而 [127, 255] 表示 [0, 128],二进制的 01111100 是十进制的 124,表示 ,最后的 23 位是二进制的小数 0.25:

4a39c70691804f2892a8b2eea8e69771.png
floating-number-example

图 5 - 0.15625 的单精度浮点数表示

通过上图中的公式 可以将浮点数的二进制表示转换成十进制的小数。0.15625 虽然还可以用单精度的浮点数精确表示,但是 0.1 和 0.2 只能使用浮点数表示近似的值:

ece35ac3177ac7a47d056ea35a3958c7.png
dot-one-dot-two-floating-number

图 6 - 0.1 和 0.2 的单精度浮点数表示

因为 0.2 和 0.1 只是指数稍有不同,所以上图中只展示了 0.1 对应的单精度浮点数,从上图的结果我们可以看出,0.1 和 0.2 在浮点数中只能用近似值来代替,精度十分有限,因为单精度浮点数的小数位为 23,双精度的小数位为 52,同时都隐式地包含首位的 1,所以它们的精度在十进制中分别是 和 位。

因为 0.1 和 0.2 使用单精度浮点数表示的实际值为 0.100000001490116119384765625 和 0.20000000298023223876953125[^7],所以它们在相加后就得到的结果与我们在一开始看到的非常相似:

5539bec5b03f84411df4aba2f377975e.png
dot-three-floating-number

图 7 - 0.1 加 0.2 的结果

上图只是使用单精度浮点数表示的数字,如果使用双精度浮点数,最终结果中的 3 和 4 之间会有更多的 0,但是小数出现的顺序是非常相似的。浮点数的运算法则相对来说比较复杂,感兴趣的读者可以自行搜索相关的资料,我们在这里不展开介绍了。

总结

当我们在不同编程语言中看到 0.300000004 或者 0.30000000000000004 时不应该感到惊讶,这其实说明编程语言正确实现了 IEEE 754 标准中描述的浮点数系统,在使用单精度和双精度浮点数时也应该牢记它们只有 7 位和 15 位的有效位数。

在交易系统或者科学计算的场景中,如果需要更高的精度小数,可以使用具有 28 个有效位数的 decimal 或者直接使用分数,不过这些表示方法的开销也随着有效位数的增加而提高,我们应该按照需要选择最合适的方法。重新回到今天的问题 — 0.1 和 0.2 相加不等于 0.3 的原因包括以下两个:

  • 使用二进制表达十进制的小数时,某些数字无法被有限位的二进制小数表示;
  • 单精度和双精度的浮点数只包括 7 位或者 15 位的有效小数位,存储需要无限位表示的小数时只能存储近似值;

浮点数系统的设计是一个比较有趣的工程问题,因为操作系统一般都是 32 位或者 64 位的,浮点数充分利用了 32/64 位的比特,将每一位的作用都发挥到极致,使用最紧凑和简洁的方式实现了尽可能高的精度。到最后,我们还是来看一些比较开放的相关问题,有兴趣的读者可以仔细思考一下下面的问题:

  • 有哪些编程语言内置了高精度的浮点数或者小数?
  • 如何实现一个可以精确表示所有实数(包括有理数和无理数)的系统?

图是怎么画的

f5a272b8e4b2a9182587a1afea548aa3.png本文使用的是Sketch

往期热门文章:

1、《历史文章分类导读列表!精选优秀博文都在这里了!》

2、图解Spring循环依赖,看过之后面试再也不用慌了!

3、他来了!IDEA 2020.1 新版介绍!不过升级前请注意避坑!

4、七个略火的Spring Boot+Vue开源项目!

5、Linux 11个炫酷的终端命令!你知道几个?

6、十个你可能不曾用过的Linux命令!巨好用!

7、分库分表  PK NewSQL数据库!

8、快给你的Spring Boot做个埋点监控吧!

9、一入职!就遇到上亿(MySQL)大表的优化....

10、惊呆了,Spring Boot居然这么耗内存!

070d2c92b70e0cac576dfb63fab8a06b.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/335229.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

在抽象类中可以没有抽象方法_是否可以在最终课程中使用抽象方法?

在抽象类中可以没有抽象方法这是最近在Java开发人员工作面试的电话面试中向我的一位读者提出的有趣的Java核心问题之一。 即使他知道你 无法用Java将抽象类定型为final ,他对方法的措辞感到困惑。 答案很简单,不,在Java的最终类中不可能有抽…

python二维列表排序_使用Python按顺时针方向排序二维坐标列表?

这应该说明问题,给出一个可视化工具 但对于在同一距离上获得一组点的正确入口点来说,这并不总是有效的import random import pylab import cmath from itertools import groupby pts [(random.randrange(-5,5), random.randrange(-5,5)) for _ in range…

微型计算机生产工艺,bb肥生产设备制造工艺流程

原标题:bb肥生产设备制造工艺流程BB肥生产设备与有机肥设备相比较而言设备相对简单,因而BB肥便具有投资小的优点,而且因其配方灵活,非常适合我国正在推广的测土配方肥的需要,是一种非常适合我国国情的肥料。在发达国家…

devc++鼠标变成了光标_Excel填充别再用鼠标拖拉了!用这4个方法,效率至少高10倍!...

Hello,各位叨友们好呀!我是叨叨君~根据下表对照一下自己,在Excel中需要批量填充公式的时候,你是不是还在用鼠标拖拉的方法,将光标放在单元格的右下角,然后按鼠标左键,向下拖动,填充完…

运动基元_开发人员的新分布式基元

运动基元面向对象的基元(进程内基元) 作为Java开发人员,我非常熟悉面向对象的概念,例如类,对象,继承,封装,多态性等。除了面向对象的概念之外,我还非常熟悉Java运行时。它…

html5网站 500.19错误,WIN7操作系统创建IIS后浏览时提示HTTP500.19错误是怎么回事?如何解决?...

WIN7操作系统创建IIS后浏览时提示HTTP500.19错误是怎么回事?如何解决?作者:兴邦开发部人气:发表时间:2015年05月18日[文章内容简介]:WIN7操作系统创建IIS后浏览时提示HTTP500.19错误是怎么回事?…

网络位置可以看到另一个人的电脑_计算机组成原理(一)- 冯·诺依曼体系结构...

1 计算机的基本硬件组成早期,DIY一台计算机,要先有三大件CPU内存主板1.1 CPU计算机最重要的核心配件,中央处理器(Central Processing Unit)。计算机的所有“计算”都是由CPU来进行的。CPU是一个超级精细的印刷电路版1.2 内存(Memory)你撰写的程序、打开的…

vaadin_Vaadin提示:以声明方式构建UI

vaadin如果您使用过GWT,那么您可能会发现UiBinder对于设计复杂的UI很有用。 在有关Vaadin的系列文章中,我们希望在Vaadin和GWT之间得出相似之处。 Vaadin提供了多种开箱即用的工具和组件,用于构建复杂且美观的UI。 其中之一是可以像UiBinder那…

关东升python从小白到大牛_《Python从小白到大牛》第3章 第一个Python程序

本章以HelloWorld作为切入点,介绍如何编写和运行Python程序代码。 运行Python程序主要有两种方式: 1.交互式方式运行 2.文件方式运行 本章介绍这两种运行方式实现HelloWorld程序。 使用Python Shell 进入Python Shell可以通过交互…

neo4j 显示名字_Neo4j:绘制“我的名字是……我在工作”图

neo4j 显示名字在过去的几天里,我一直在关注DHH发起的有关“我的名字是……”的推文。 据我了解,其想法是表明在白板上编写采访谜语/艰巨任务是荒谬的。 您好,我叫大卫。 我不会在白板上写气泡排序。 我一直在互联网上查找代码。 我不做谜语…

Final Cut Pro x(FCPX)调色笔记

文章目录一、注意点二、调色流程1. 颜色校正(一级校色)1.1 颜色转换即色彩空间转换1.2 降噪(noise reduction 即NR)1.3 调整曝光和对比度1.4 调整白平衡1.5 饱和度1.6 肤色调整2.二级校色2.1 突出人物主体的方法一2.2 突出人物主体…

axure web组件下载_实践干货:Axure插入图标的4种办法

编辑导读:图标是我们在制作产品原型的时候使用的比较多的一类素材,在日常绘制原型的时候一般是以插入的形式添加到Axure中。本文作者结合自身经验,介绍了四种Axure中引入图标的方法,希望对大家能有所帮助。在日常绘制原型的时候&a…

上师大计算机学院分数线,分数低还想上师范大学?这4所师范院校,二本的分数就够了...

截至目前,全国各省市高考成绩全部公布了,接下来最主要的工作就是填报志愿,选择适合自己的大学和专业。每年到这个时候,就有不少家长和考生问我,自己的分数较低,不够一本线,有没有比较好的师范大…

上古卷轴3晨风职业_巫师3:上古卷轴5老玩家,入手巫师3,体验昆特牌版“实验室”...

今天小编入手了,期待已久的《巫师3》,而作为一个《上古卷轴5》的“老油条”,奇趣君下面说一下,一个老滚5的“老油条”玩《巫师3》是什么样的体验。首先我进入了开场动画,我没有跳过,而是看着他的剧情&#…

MacBook Mac OS 无法识别移动硬盘的解决办法

文章目录方法一、打开系统信息 System Information方法二、打开磁盘工具 Disk Utility方法一、打开系统信息 System Information 打开「系统信息」,点击左侧硬件列表的 USB,在右侧找到你的移动硬盘点击查看,如下图所示: 然后打开…

mysql没有开启binlog能恢复数据吗_一个妹纸rm -rf把公司整个数据库删没了...

经历了两天不懈努力,终于恢复了一次误操作删除的生产服务器数据。对本次事故过程和解决办法记录在此,警醒自己,也提示别人莫犯此错。也希望遇到问题的朋友能找到一丝灵感解决问题。事故背景安排一个妹子在一台生产服务器上安装 Oracle&#x…

头条号个人中心登录_头条号平台上线「插入小程序」功能

头条号平台上线「插入小程序」功能,创作者可在图文、小视频和自定义菜单中插入头条小程序,帐号服务能力和变现能力进一步提升。一、什么是「头条小程序」?「头条小程序」是为内容生产者提供的延伸变现工具,是对创作者内容服务的延…

stearm计算机验证码,steam账户名称怎么取,值得收藏

steam是计算机游戏界最大的数码发行平台,是一个游戏整合下载平台,很多喜欢玩游戏的朋友都会用这个软件,当然也不少刚开始使用这个软件的朋友,这些朋友因为才刚刚接触到这个软件所以不知道steam账户名称怎么取,不要担心…

造完家怎么拆东西_地弹簧玻璃门怎么拆?地弹簧玻璃门拆除注意事项有哪些?...

现如今,我们总可以看到玻璃门的身影,在我们的生活中,玻璃门可以说是随处可见。而对于安装玻璃门,大家了解多少呢?为了更好认识玻璃门,今天就带大家一起走进玻璃门的安装中,告诉大家怎么样拆卸和组装玻璃门…

dubbo provider异步_Dubbo学习(六) Dubbo面试问题

Dubbo是Alibaba开源的分布式服务框架,它最大的特点是按照分层的方式来架构,使用这种方式可以使各个层之间解耦合(或者最大限度地松耦合)。从服务模型的角度来看,Dubbo采用的是一种非常简单的模型,要么是提供方提供服务&#xff0c…