js中精度问题以及解决方案
js中的数字按照IEEE 754的标准,使用64位双精度浮点型来表示。其中符号位S,指数位E,尾数位M分别占了1,11,52位,并且在ES5规范中指出了指数位E的取值范围是[-1074, 971]
。
精度问题汇总
想用有限的位来表示无穷的数字,显然是不可能的,因此会出现一些列精度问题:
- 浮点数精度问题,比如
0.1 + 0.2 !== 0.3
- 大数精度问题,比如
9999 9999 9999 9999 == 1000 0000 0000 0000 1
- toFixed四舍五入结果不准确,比如
1.335.toFixed(2) == 1.33
浮点数精度和toFixed其实属于同一类问题,都是由于浮点数无法精确表示引起的,如下:
(1.335).toPrecision(20); // "1.3349999999999999645"
而关于大数精度问题,我们可以先看下面这个代码片段:
/ 能精确表示的整数范围上限,S为1个0,E为11个0,S为53个1
Math.pow(2, 53) - 1 === Number.MAX_SAFE_INTEGER // true
// 能精确表示的整数范围下限,S为1个1,E为11个0,S为53个1
-(Math.pow(2, 53) - 1) === Number.MIN_SAFE_INTEGER // true
// 能表示的最大数字,S为1个0,E为971,S为53个1
(Math.pow(2, 53) - 1) * Math.pow(2, 971) === Number.MAX_VALUE // true
// 能表示的最接近于0的正数,S为1个0,E为-1074,S为0
Math.pow(2, -1074) === Number.MIN_VALUE // true
通过以上可以明白,[MIN_SAFE_INTEGER, MAX_SAFE_INTEGER]的整数都可以精确表示,但是超出这个范围的整数就不一定能精确表示。这样就会产生所谓的大数精度丢失问题。
解决思路
首先考虑的是如何解决浮点数运算的精度问题,有3种思路:
- 考虑到每次浮点数运算的偏差非常小(其实不然),可以对结果进行指定精度的四舍五入,比如可以
parseFloat(result.toFixed(12))
; - 将浮点数转为整数运算,再对结果做除法。比如0.1 + 0.2,可以转化为
(1*2)/3
。 - 把浮点数转化为字符串,模拟实际运算的过程。
先来看第一种方案,在大多数情况下,它可以得到正确结果,但是对一些极端情况,toFixed到12是不够的,比如:
210000 * 10000 * 1000 * 8.2 // 17219999999999.998
parseFloat(17219999999999.998.toFixed(12)); // 17219999999999.998,而正确结果为17220000000000
上面的情况,如果想让结果正确,需要toFixed(2)
,这显然是不可接受的。
再看第二种方案,比如number-precision这个库就是使用的这种方案,但是这也是有问题的,比如:
// 这两个浮点数,转化为整数之后,相乘的结果已经超过了MAX_SAFE_INTEGER
123456.789 * 123456.789 // 转化为(123456789 * 123456789)/1000000,结果是15241578750.19052
所以,最终考虑使用第三种方案,目前已经有了很多较为成熟的库,比如bignumber.js,decimal.js,以及big.js等。我们可以根据自己的需求来选择对应的工具。并且,这些库不仅解决了浮点数的运算精度问题,还支持了大数运算,并且修复了原生toFixed结果不准确的问题。
题外话
还有另外一个与js计算相关的问题,即Math.round(x),它虽然不会产生精度问题,但是它有一点小陷阱容易忽略。下面是它的舍入的策略:
- 如果小数部分大于0.5,则舍入到下一个绝对值更大的整数。
- 如果小数部分小于0.5,则舍入到笑一个绝对值更小的整数。
- 如果小数部分等于0.5,则舍入到下一个正无穷方向上的整数。
所以,对Math.round(-1.5),其结果为-1,这可能不是我们想要的结果。
当然,上面提到的big.js等库,都提供了自己的round函数,并且可以指定舍入规则,以避免这个问题。
js中精度问题以及解决方案的更多相关文章
- JavaScript 中精度问题以及解决方案
JavaScript 中的数字按照 IEEE 754 的标准,使用 64 位双精度浮点型来表示.其中符号位 S,指数位 E,尾数位M分别占了 1,11,52 位,并且在 ES5 规范 中指出了指数位E ...
- javascript(js)小数精度丢失的解决方案
原因:js按照2进制来处理小数的加减乘除,在arg1的基础上 将arg2的精度进行扩展或逆扩展匹配,所以会出现如下情况. javascript(js)的小数点加减乘除问题,是一个js的bug如0.3* ...
- 关于js中异步问题的解决方案
在js中有一个始终无法绕过的问题,如何优雅地解决异步问题.实际上,js在执行过程中,每遇到一个异步函数,都会将这个异步函数放入一个异步队列中,只有当同步线程执行结束之后,才会开始执行异步队列中的函数, ...
- JS中遍历EL表达式中后台传过来的Java集合
前言:在我的项目里有这么一个情况,后台直接model.addAttribute()存储了一个对象,此对象内部有一个集合,前端JSP处理的方法正常情况下就是直接使用EL表达式即可.但是如果在JS中需要使 ...
- js中进行金额计算 parseFloat 会产生精度问题
在js中进行以元为单位进行金额计算时 使用parseFloat会产生精度问题 var price = 10.99;var quantity = 7;var needPay = parseFloat(p ...
- js中如何取精度
js中如何取精度 一.总结 一句话总结:其实round()函数去经度会有误差,直接用num.toFixed(2)简单方便. toFixed()方法会按照指定的小数返回数值的字符串表示.var num ...
- 小程序首页onLoad为异步,调用app.js中的全局参数的解决方案。
一,先说一下遇到的问题: 在首页,为了携带app.js中一些参数去做请求动作,但是由于异步原因,发现请求时候,参数信息还未获取到但请求已经发出去. 若等app.js的全局参数返回来,再携带着它去做请求 ...
- 计算价格, java中浮点数精度丢失的解决方案
计算价格, java中浮点数精度丢失的解决方案
- Long类型转json时前端js丢失精度解决方案
一.问题背景 Java后端开发过程中,尤其是id字段,因数值太大,通过json形式传输到前端后,在js解析时,会丢失精度. 如果对精度丢失没有什么概念,可以看一个知乎的帖子,来感受一下:https:/ ...
随机推荐
- day19-网络编程基础(二)
今天没有很多概念性的东西,主要是方法性的东西以及编程的一些方法吧 今日份目录 1.UDP传输的特点以及实验 2.UTP与UDP传输的区别 3.基于tcp的low版带验证功能的FTP小程序 4.基于so ...
- python3 今日大纲 day05
1. 上周内容回顾 1. 闭包: 内层函数对外层函数变量的使用 def outer(): a = 10 def inner(): print(a) return inner ret = outer() ...
- dede 5.7 任意用户重置密码前台
返回了重置的链接,还要把&删除了,就可以重置密码了 结果只能改test的密码,进去过后,这个居然是admin的密码,有点头大,感觉这样就没有意思了 我是直接上传的一句话,用菜刀连才有乐趣 ...
- 【Atcoder Grand Contest 011 F】Train Service Planning
题意:给\(n+1\)个站\(0,\dots,n\),连续的两站\(i-1\)和\(i\)之间有一个距离\(A_i\),其是单行(\(B_i=1\))或双行(\(B_i=2\)),单行线不能同时有两辆 ...
- 使用sz/rz基于串口传输文件
关键词:lrzsz.minicom.ZMODEM.MD5sum等. 在环境受限的嵌入式系统上,往往只有串口可以使用. 此时如果需要传输文件,需要借助rz/sz工具,可以使用的传输协议有ZMODEM.Y ...
- Linux内存管理 (10)缺页中断处理
专题:Linux内存管理专题 关键词:数据异常.缺页中断.匿名页面.文件映射页面.写时复制页面.swap页面. malloc()和mmap()等内存分配函数,在分配时只是建立了进程虚拟地址空间,并没有 ...
- JavaWeb工程中web.xml基本配置(转载学习)
一.理论准备 先说下我记得xml规则,必须有且只有一个根节点,大小写敏感,标签不嵌套,必须配对. web.xml是不是必须的呢?不是的,只要你不用到里面的配置信息就好了,不过在大型web工程下使用该文 ...
- CF1120D Power Tree
沙发~~ 题意简述 给你一棵有根树,定义叶子为度数为1的点. 你可以以$ w_x \(的代价控制\)x\(点.选择控制之后可以给它的子树里的叶子加 上\)t (t \in Z )$. 你要以最小的总代 ...
- iOS开发基础-图片切换(1)
一.程序功能分析 1)点击左右箭头切换图片.序号.描述: 2)如果是首张图片,左边箭头失效: 3)如果是最后一张图片,右边箭头失效. 二.程序实现 定义确定图片位置.大小的常量: //ViewCont ...
- python的web运用
---恢复内容开始--- 对于大多数学过编程语言的人来说都知道大部分的编程语言都可以用来开发web运用,对于python来说也是可以的,不过对于web开发来说用python你可以选择 两个不同的框架, ...