JavaScript精度丢失问题
JavaScript精度丢失问题。
-
javaScript中臭名昭著的BUG就是
0.1+0.2 !== 0.3
,因为精度问题,导致所有浮点数运算都是不安全的。 -
正如下面的计算结果,它们并不是我们所预想的:
0.1 + 0.2 = 0.30000000000000004
1 - 0.9 = 0.09999999999999998
-
虽然很多人知道这个浮点数误差这个问题的,可是却不知道背后的原理以及解决方案。今天我们就通过上面两个例子看看JavaScript浮点数误差问题背后的原理以及解决方案吧!
-
那我们先来看看本文将包含什么内容
-
为什么JavaScript的所有数值都统称为Number -
是什么导致的浮点数计算误差问题(IEEE 754是什么) -
那遇到浮点数计算应该如何解决 -
最后讲讲JavaScript值的范围
为什么JavaScript中所有的数值类型都称为Number类型
我们通过ECMAScript看看。
在ECMAScript标准中我们可以看到对Number类型的定义是这样的,使用IEEE 754格式表示整数和浮点值(JavaScript使用的是64位,也就是常说的'双精度')。
那为什么呢?因为存储浮点值是存储整数值的两倍,因此ECMAScript总是想方设法把把值转换位整数。这样的存储结构优点是可以归一化处理整数和小数,节省存储空间。
什么导致浮点数计算的误差问题?IEEE 754是什么?
-
因为JavaScript中是遵循IEEE 754的标准,在程序的内部Number类型实质是一个64位固定长度的浮点数,也就是标准的double双精度浮点数。
-
IEEE 754 是IEEE二进制浮点数算数标准。格式如下
V = (-1)^s (1+M) 2^(E-127)(单精度)
V = (-1)^s (1+M) 2^(E-1023)(双精度)
-
那我们来看看十进制的数值是如何按照IEEE 754进行转换的
-
十进制小数 3.14转换二进制 3.14 = 11.001000111101011100001010001111010111000010100011111 = 1.1001000111101011100001010001111010111000010100011111 x 21
-
根据上面的公式
-
符号位:0
-
阶码部分:64位为例,1023+(1)= 1024,二进制就是10000000000
-
尾数部分:
64位为例,应为52位,1001000111101011100001010001111010111000010100011111
-
结果为 :0100000000001001000111101011100001010001111010111000010100011111 刚好64位,大家可以数数。
再来说说为什么阶码那里要用1023+1呢?
-
因为E 在64位的时候为11位,转换10进制也就是2047,但是IEEE 754又规定要减去中间值,也就是1023,所以上面就是 1023+1
那如果遇到浮点数的计算问题该怎么办呢?
一、类库部分
Math.js
math.js是JavaScript和Node.js的一个广泛的数学库。支持数字、大数、分数、单位和矩阵数据类型的运算。
官网:https://mathjs.org/
GitHub:https://github.com/josdejong/mathjs
经典问题 0.1+0.2
var math = require('mathjs');
console.log(math.add(0.1,0.2)); //0.30000000000000004
console.log(math.format((math.add(math.bignumber(0.1),math.bignumber(0.2))))); //'0.3
big.js
-
用于任意精度的十进制算术的小型JavaScript库
-
Github :https://github.com/MikeMcl/big.js/
var Big = require("big.js");
x = new Big(0.1);
y = 0.2;
console.log(x.plus(y).toString())//'0.3'
二、原生方法
Number.prototype.toFixed()
-
toFixed()方法是使用定点表示法格式化一个值,对结果进行四舍五入 -
toFixed(),精度必须在0-20之间
parseFloat((0.1+0.2).toFixed(10)); //0.3
parseFloat((0.3/0.1).toFixed(10)); //3
parseFloat((1-0.9).toFixed(10)); //0.1
值的范围
-
由于内存的限制,ECMAScript并不支持表示这个世界上所有的数值。ECMAScript可以表示的最小值保存在
Number.MIN_VALUE
中,这个值在浏览器是5e-423
;可以表示的最大值保存在Number.MAX_VALUE
中,这个值在浏览器中是1.7976931348623157e+308
。 -
简单介绍了以后,来说说为什么要说值的范围。
-
因为还有两个值没有说,
Number.MAX_SAFE_INTEGER
最大安全整数
Number.MIN_SAFE_INTEGER
最小安全整数
-
其实上面我们说了那么多都是再说精度丢失,但是最根本的原因在于哪,就是因为有范围的限制。
Number.MAX_SAFE_INTEGER // 9007199254740991
1111111111111111+22222222222222222 = 23333333333333336
当我们的数值超过了值的范围进行操作就会出现精度的丢失
-
那为什么要存在他们呢?因为在此范围内整数和双精度浮点数是一一对应的,不存在一个整数有多个浮点数的情况,当然也不会又一个浮点数对应多个整数的情况。
本文分享自微信公众号 - 前端巅峰(Java-Script-)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
在Ant Design 4.0里,我们如何追求快乐的工作?
在前不久的上海外滩大会上,蚂蚁集团高级体验设计专家林外分享了Ant Design4.0背后的设计理念,我们将内容整理出来与大家分享。 今天,我和大家分享的话题叫做,创造快乐工作。 Ant Design的基本假定 在我开始所有话题之前,我有问题想问大家,大家工作快乐吗? 我听到了特别积极的反应,说非常的快乐。 但是呢,其实,工作并没有我们想象中那么快乐,是所有的活动当中快乐指数最低的,跟躺着带来的快乐差不多的,有些人躺着什么也不干,也比工作快乐。 什么原因导致了工作的不快乐?大部分人认为工作是为老板服务,所以很难受。另一类人是因为反馈,很多工作的结果依靠于外界,依靠于老板,所以你跟直属上司的关系,决定了工作的体验。 第三类是我们认为挑战和技能的不匹配,导致了我们工作的不快乐。当挑战大于技能的时候,你就会焦虑,当技能大于挑战的时候,你就会觉得无聊,你的工作就会在焦虑和无聊之间来回地徘徊,这是我们理解的世界。 这个问题,在数字世界中会变得更加的明显。70 年前,第一台计算机出来之后能解决的问题非常的简单,但是 70 几年过去了,数字世界得到了非常大的发展,我身边任何一个小设备都远远大于 70...
- 下一篇
技术分享 | 使用 Python 解析并“篡改”MySQL 的 Binlog
作者:姚远 专注于 Oracle、MySQL 数据库多年,Oracle 10G 和 12C OCM,MySQL 5.6,5.7,8.0 OCP。现在鼎甲科技任技术顾问,为同事和客户提供数据库培训和技术支持服务。 本文来源:原创投稿 *爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 前言 MySQL 的 Binlog 记录着 MySQL 数据库的所有变更信息,了解 Binlog 的结构可以帮助我们解析Binlog,甚至对 Binlog 进行一些修改,或者说是“篡改”,例如实现类似于 Oracle 的 flashback 的功能,恢复误删除的记录,把 update 的记录再还原回去等。本文将带您探讨一下这些神奇功能的实现,您会发现比您想象地要简单得多。本文指的 Binlog 是 ROW 模式的 Binlog,这也是 MySQL 8 里的默认模式,STATEMENT 模式因为使用中有很多限制,现在用得越来越少了。 Binlog 的结构 Binlog 由事件(event)组成,请注意是事件(event)不是事务(transaction),一个事务可以包含多个事件。...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- SpringBoot2全家桶,快速入门学习开发网站教程
- CentOS8编译安装MySQL8.0.19
- CentOS7,CentOS8安装Elasticsearch6.8.6
- SpringBoot2编写第一个Controller,响应你的http请求并返回结果
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS8,CentOS7,CentOS6编译安装Redis5.0.7
- Red5直播服务器,属于Java语言的直播服务器
- CentOS6,CentOS7官方镜像安装Oracle11G
- SpringBoot2更换Tomcat为Jetty,小型站点的福音
- SpringBoot2整合Thymeleaf,官方推荐html解决方案