JavaScript浮点运算0.2+0.1 !== 0.3

浮点运算JavaScript

本文主要讨论JavaScript的浮点运算,主要包括

  • JavaScript number基本类型

  • 二进制表示十进制

  • 浮点数的精度

number 数字类型

在JavaScript中,数字只有number这一种类型;

var intS = 2,floatA = 0.1;
typeof intS;   // number
typeof floatA; //number

那么这个情况下应该很容易理解一件事情:number应该是实现的浮点型数来标识所有的数;
而实际上也是这样;JavaScript的number类型按照ECMA的JavaScript标准,它的Number类型就是IEEE 754的双精度数值,相当于java的double类型。IEEE 754标准《二进制浮点数算法》(www.ieee.org)就是一个对实数进行计算机编码的标准。

十进制转换为二进制

同样,在计算机的世界里,应该是只有二进制数据的,不是0就是1,那么为了表达生活中最为常见的十进制数据,就会有个转换过程;这个就是十进制转换为二进制的方法;
参考:http://www.cnblogs.com/xkfz00...

十进制整数转换为二进制

这个情况比较常见:3 =》 01;5 =》101;十进制整数转换为二进制整数采用"除2取余,逆序排列"法。具体做法是:用2去除十进制整数,可以得到一个商和余数;再用2去除商,又会得到一个商和余数,如此进行,直到商为零时为止,然后把先得到的余数作为二进制数的低位有效位,后得到的余数作为二进制数的高位有效位,依次排列起来
换算的法则是,使用一个十进制数字来示例: 173 =》 10101101:
图片描述

十进制小数变为二进制

十进制的小数转换为二进制,0.5 =》 0.1 ;十进制小数转换成二进制小数采用"乘2取整,顺序排列"法。具体做法是:用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数 部分,又得到一个积,再将积的整数部分取出,如此进行,直到积中的小数部分为零,或者达到所要求的精度为止。然后把取出的整数部分按顺序排列起来,先取的整数作为二进制小数的高位有效位,后取的整数作为低位有效位。
示例 0.8125 =》 0.1101
图片描述

完整的十进制小数转为二进制

从上面的讲述中可以知道,一个十进制的小数:173.8125 转换为二进制是 10101101.1101;在计算机中一般都会使用科学计算来处理浮点数,也就是 173.8125 == 1.738125 * 10(2);那么二进制的表示也不例外,通过指数来定位小数点,用固定的精度来表示数据;

在JavaScript使用的IEEE 754的双精度数值,一个JavaScript的number表示应该是二进制如下格式:

 1[-/+] 11[位指数]        52[数值]                 64位长
+  -  + -------- + ----------------------- +

64位的具体表述在不同系统可能顺序会有差异,但是都是包含以下三部分:

  1. 符号位: 1bit,0表示正数,1表示负数

  2. 指数位:11bit,也就是需要移动的位数,也就是指数的大小;由于会存在负数和证书,所以这里用了一个偏移的方式处理,也就是真正的指数+1023,这样的话就表示了【-1023 ~ 1024】;而-1023也就是全0,1024就是全1;

  3. 尾数:52bit,这里需要注意的是由于小数点前面以为必须为1,所以实际上是52+1=53位;

参考:http://coolcao.com/2016/10/12...
http://www.cnblogs.com/kingwo...
可以看到,由于二进制的精确位数只有52+1位,那么类似 1/3 这样的无理数,那么肯定是无法表示的,而且二进制还有很多有理数 0.1这样的也无法在52位精度的范围内表示精确无误;都会被截取53位以后的所有数字。

0.1+0.2 !== 0.3 [true]

有了以上的铺垫,那么我们很容易就可以推到出原因了;推理步骤如下:

十进制0.1 =》 [利用上面说的方法来转换,乘以2取整数,然后顺序获取取出得数]

 =>二进制为:0.0001100110011[0011…](循环0011,无限循环)   =>指数表示:尾数为1.1001100110011001100…1100(共52位,除了小数点左边的必须为1的数据),指数为-4(-4+1023 = 1019 二进制移码为 01111111011),符号位为0  => 计算机存储为:0 01111111011 10011001100110011…11001  => 因为尾数最多52位,所以实际存储的值为0.00011001100110011001100110011001100110011001100110011001  

而十进制0.2

 => 二进制0.0011001100110011…(循环0011)  =>尾数为1.1001100110011001100…1100(共52位,除了小数点左边的1),指数为-3(-3+1023=1020二进制移码为01111111100),符号位为0  => 存储为:0 01111111100 10011001100110011…11001  因为尾数最多52位,所以实际存储的值为0.00110011001100110011001100110011001100110011001100110011  

 那么两者相加得:
加法运算的时候需要注意以下几点:

  • 对阶:需要将指数小的,变得和指数大的一样,通过位数移位【移位注意有一个隐藏的小数点左边的固定的1】

  • 尾数运算:加法运算

  • 结果规格化:规范为 位数的左边第一位必须为隐藏的1,

  • 舍入处理:主要是在截取的时候进行的处理,最后位舍去时为0直接舍去,为1则+1;【有多种舍入处理】

  • 溢出判断:

尾数加法运算开始,注意小数点左边隐藏的默认1

   [1].1001100110011001100110011001100110011001100110011001+ [1].1001100110011001100110011001100110011001100110011001

//由于0.1是-3阶,指数是-4,而0.2的指数位-3,故而取大者-3;这样0.1需要右移一位,刚好之前小数点左侧隐藏的1被移出来了;如下

      .1100110011001100110011001100110011001100110011001100 【1被舍去】
+  [1].1001100110011001100110011001100110011001100110011001
=   100110011001100110011001100110011001100110011001100111

此时阶码变为了 -3,但是由于进位了两位,但是最高位需要保留,故而阶位只是+1,也就是-2了.也就是01111111101,
进行舍入处理,由于最高位一定是1,所以对结果最高位去除,末尾一位去除,由于是1,故而+1处理,得到新的52位位数为:

 新的尾数: 0011001100110011001100110011001100110011001100110100
存储为: 0  01111111101  0011001100110011001100110011001100110011001100110100
十进制就是:0.3000000000000000444089209850062616169452667236328125
截取为:   0.30000000000000004  

转换成10进制之后得到:0.30000000000000004

思考

看到 0.1+0.2 = 0.30000000000000004;我开始慌了,那么0.1+0.3 === 0.4 对吗?我也不知道,虽然最后运算的时候证明是对的,但是还是可以按照我们的方法进行分析

 十进制0.1  [利用上面说的方法来转换,乘以2取整数,然后顺序获取取出得数]=>二进制为:0.0001100110011[0011…](循环0011,无限循环)   =>指数表示:尾数为1.1001100110011001100…1100(共52位,除了小数点左边的必须为1的数据),指数为-4(-4+1023 = 1019 二进制移码为 01111111011),符号位为0  => 计算机存储为:0 01111111011 10011001100110011…11001  => 因为尾数最多52位,所以实际存储的值为0.00011001100110011001100110011001100110011001100110011001 而十进制0.3  => 二进制0.010011001100110011001100110011001...(循环1001)  =>尾数为1.00110011001100110011…0011(共52位,除了小数点左边的1),指数为-2(-2+1023=1021二进制移码为01111111101),符号位为0  => 存储为:0 01111111101 0011001100110011…110011  因为尾数最多52位,所以实际存储的值为0.01001100110011001100110011001100110011001100110011001100  那么两者相加得[对阶,为大者-2,-4阶数的0.1左移两位]:      .0110011001100110011001100110011001100110011001100110
+ [1].0011001100110011001100110011001100110011001100110011 
=   1.1001100110011001100110011001100110011001100110011001新的尾数: 1001100110011001100110011001100110011001100110011001
存储为: 0  01111111101  1001100110011001100110011001100110011001100110011001
十进制就是:0.39999999999999996447286321199499070644378662109375
截取为:   0.4 

可以看到,JavaScript的小数保留了17位,

//一个52位小数的最小二进制的表示
0.0000000000000000000000000000000000000000000000000001
0.0000000000000002220446049250313 
//一个53【加头部默认1位】位小数的最小二进制数
0.00000000000000000000000000000000000000000000000000001
0.00000000000000011102230246251565
Math.pow(2, 53)
9007199254740992 //当大于这个数的时候就会丢失精度
Math.pow(2, -53)
1.1102230246251565e-16  //当小于这个数也会丢失精度

JavaScript采用了17位来默认截取数据,根据四舍五入方法或者是说二进制中的0舎1进位的方式截取。
所以这样的加法有的时候会出现精度问题,有的又不会。看看具体的情况,在chrome的console里面运行的结果如下:

0.4-0.1
0.300000000000000040.3+0.1
0.40.1+0.2
0.30000000000000004

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

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

相关文章

三菱模拟量输入与输出程序_初学PLC是学习西门子还是三菱?

PLC的种类繁多,品牌大多分为欧系、日系、美系。德系PLC以西门子为主,日系有三菱、欧姆龙、松下……,美系有罗克韦尔(A-B)通用电气(GE)公司、莫迪(MODICON)公司等。美国和欧洲的PLC技术是在相互隔离情况下独立研究开发的,因此美国和…

性能测试十四:Xshell链接linux虚拟机

一、先装一个linux虚拟机 VBoxcentos1、先下载Linux镜像文件的ovf或者OVA文件2、打开vbox,点击菜单栏“管理”-“导入虚拟电脑3、选择解压路径中的ovf或者OVA文件,点击下一步 4、点击“导入”,等待完成5、导入成功后,选择新导入的…

html5进度条插件 传递参数,Html5进度条插件(自写)

(function () {window.H5ProgressBar function (obj) {this.height obj.height;this.width obj.width;this.speed obj.speed;};//在界面上布局元素H5ProgressBar.prototype.drawLayout function () {document.write("开始下载")document.write(" ")do…

html网页设计要点,网站交互设计的8个要点

一、力求一致性例如网站首页需要和每一个下级页面保持一致的风格,导航都要放在屏幕的左上角,具有高度一致性的界面能给人清晰整洁的感觉。二、允许频繁使用快捷键快捷键表示产品使用的灵活性和有效性,想想每次我们使用搜索引擎的时候是鼠标点…

搭建nfs共享存储服务之二nfs服务端配置

1.1.NFS服务端配置文件路径为: /etc/exports,并且默认为空,需要用户自行配置。/etc/exports文件配置格式为:NFS共享的目录 NFS客户端地址1(参数1,参数2...)客户端地址2(参数1&#x…

值大于为此列指定的允许精度_电能质量测试精度会受到哪些因素影响?如何解决?...

关于电能质量(也称为PQ:Power Quality)研究的主题已成为多方面的话题。其需要考虑的不仅仅是IEC 61000-x-x电磁兼容性标准中规定的实际电能质量现象。在实践中,通常还会增加其他重要参数来保证供电的安全性,在某些情况下这些参数甚…

前端websocket获取数据后需要存本地吗_是什么让我放弃了restful api?了解清楚后我全面拥抱GraphQL...

GraphQL初步认识背景REST作为一种现代网络应用非常流行的软件架构风格,自从Roy Fielding博士在2000年他的博士论文中提出来到现在已经有了20年的历史。它的简单易用性,可扩展性,伸缩性受到广大Web开发者的喜爱。REST 的 API 配合JSON格式的数…

计算机应用基础案例教程总结,计算机应用基础案例教程

包杰军等编著的《计算机应用基础案例教程》以培养职业能力为目标,本着“做学合一”、“理论与实践并行”、“知识与技能并重”的教育思想编写。本书将实际操作案例与教学内容紧密结合,结构清晰、内容翔实、图文并茂、实用性强。全书共分6章,第…

ios开发之--UIDocumentInteractionController的使用(实现更多分享服务)

最近在做项目的时候,碰到这样一个需求,就是本地生成pdf文件,然后本地打开,经过测试发现,pdf文件是无法保存到相册里面的,只能存到手机里面,鉴于苹果的存储机制,需要取出来&#xff0…

eclipse tomcat新建一个_Javaweb07-Eclipse自动创建动态web项目

学习笔记是参考的how2j使用Eclipse创建Dynamic Web Project前面的web项目都是通过手动创建的,现在使用eclipse EE自动创建动态web项目,熟悉一下创建流程,仍旧使用前面创建过的HelloServlet。需要注意的是,这里的tomcat版本变了&am…

cordova

命令行 npm install -g cordova cordova create MyApp cd MyApp cordova platform add android 当然也可以把android换成browser把自己的前端程序放在www文件夹内这里注意如果用android studio打包或运行的话,(即不用cordova),要把…

excel导出_SpringBoot实现快速导出Excel

阅读本文约需要6分钟 大家好,我是你们的导师,我每天都会在这里给大家分享一些干货内容(当然了,周末也要允许老师休息一下哈)。上次老师跟大家分享了下MyBatis 几种通用的写法的相关知识,今天跟大家分享SpringBoot实现快速导出Exce…

fifo算法_缓存算法FIFO、LFU、LRU

阅读文本大概需要3分钟。0x01:FIFO算法FIFO(First in First out),先进先出。其实在操作系统的设计理念中很多地方都利用到了先进先出的思想,比如作业调度(先来先服务),为什么这个原则在很多地方都会用到呢?因为这个原则…

怎样设置计算机远程桌面,电脑如何设置远程连接,手把手教你如何远程

说起远程桌面很多用户都认为是从WIN2000 SERVER才开始引入的,实际上我们可以在WIN98甚至是DOS中看到他的身影。远程桌面采用的是一种类似TELNET的技术,他是从TELNET协议发展而来的。那么如何设置自动开机,下面,我们就来看看如何设…

inputstream转fileinputstream对象_FileInputStream类:文件字节输入流

API ----IO ----字节输入输出流练习 java.lang.Object 继承者 java.io.InputStream 继承者 java.io.FileInputStreampublic FileInputStream类速查速记:直接包装File用于从记事本中读数据 in是针对java来说的,从记事本读入到java* 构造方法:…

IBM将推NVMe存储解决方案

先前,IBM曾对外宣称将开发新的NVMe解决方案,并推动行业参与者进一步探索新协议,以支持更快的数据传输。周日,IBM表示新的语言协议——NVMe(非易失性存储器)正在逐步取代SAS和SATA等旧有的固态硬盘存储标准。…

BZOJ 1113: [Poi2008]海报PLA

1113: [Poi2008]海报PLA Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 1025 Solved: 679[Submit][Status][Discuss]Description N个矩形,排成一排. 现在希望用尽量少的矩形海报Cover住它们. Input 第一行给出数字N,代表有N个矩形.N在[1,250000] 下面N行,每行给出矩形的长…

opengl三维图形图形颜色_【图形学基础】基本概念

右手坐标系。类似OpenGL遵循的右手坐标系:首先它是三维的笛卡尔坐标系:原点在屏幕正中,x轴从屏幕左向右,最左是-1,最右是1;y轴从屏幕下向上,最下是-1,最上是1;z轴从屏幕里…

xp职称计算机考试题库,2015年职称计算机考试XP题库.doc

2015年职称计算机考试XP题库.doc (7页)本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦!9.90 积分2015年职称计算机考试XP题库职称计算机考试考点精编:工具栏的设置与操作XP中将…

第一个python爬虫_Python爬虫01——第一个小爬虫

Python小爬虫——贴吧图片的爬取 在对Python有了一定的基础学习后,进行贴吧图片抓取小程序的编写。 目标: 首先肯定要实现图片抓取这个基本功能 然后实现对用户所给的链接进行抓取 最后要有一定的交互,程序不能太傻吧 一、页面获取 要让pytho…