JavaScript 中精度问题以及解决方案
JavaScript 中的数字按照 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结果不准确的问题。
题外话
还有另外一个与 JavaScript 计算相关的问题,即 Math.round(x),它虽然不会产生精度问题,但是它有一点小陷阱容易忽略。下面是它的舍入的策略:
- 如果小数部分大于 0.5,则舍入到下一个绝对值更大的整数。
- 如果小数部分小于 0.5,则舍入到下一个绝对值更小的整数。
- 如果小数部分等于 0.5,则舍入到下一个正无穷方向上的整数。
所以,对 Math.round(-1.5),其结果为 -1,这可能不是我们想要的结果。
当然,上面提到的 big.js 等库,都提供了自己的 round 函数,并且可以指定舍入规则,以避免这个问题。
原文地址:https://xwjgo.github.io/2018/03/17/js%E4%B8%AD%E7%B2%BE%E5%BA%A6%E9%97%AE%E9%A2%98%E5%8F%8A%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88/
JavaScript 中精度问题以及解决方案的更多相关文章
- js中精度问题以及解决方案
js中的数字按照IEEE 754的标准,使用64位双精度浮点型来表示.其中符号位S,指数位E,尾数位M分别占了1,11,52位,并且在ES5规范中指出了指数位E的取值范围是[-1074, 971]. ...
- Javascript中递归造成的堆栈溢出及解决方案
关于堆栈的溢出问题,在Javascript日常开发中很常见,Google了下,相关问题还是比较多的.本文旨在描述如何解决此类问题. 首先看一个实例(当然你可以使用更容易的方式实现,这里我们仅探讨递归) ...
- [转载]JavaScript 中小数和大整数的精度丢失
标题: JavaScript 中小数和大整数的精度丢失作者: Demon链接: http://demon.tw/copy-paste/javascript-precision.html版权: 本博客的 ...
- javascript中可处理的浮点数的最高精度(和小数的一些小特性)
1.之前在度娘那找了一下关于javascript中可处理的浮点数的最高精度的问题,但找了好久也找不到,于是自己 小小的研究了一下,之前以为是17,后来测到18,再后来又测到19,经过一系列的改写,得到 ...
- 关于JavaScript中计算精度丢失的问题
摘要: 由于计算机是用二进制来存储和处理数字,不能精确表示浮点数,而JavaScript中没有相应的封装类来处理浮点数运算,直接计算会导致运算精度丢失. 为了避免产生精度差异,把需要计算的数字升级(乘 ...
- 计算价格, java中浮点数精度丢失的解决方案
计算价格, java中浮点数精度丢失的解决方案
- 在 JavaScript 中,我们能为原始类型添加一个属性或方法吗?
原始类型的方法 JavaScript 允许我们像使用对象一样使用原始类型(字符串,数字等).JavaScript 还提供了这样的调用方法.我们很快就会学习它们,但是首先我们将了解它的工作原理,毕竟原始 ...
- 面试说:聊聊JavaScript中的数据类型
前言 请讲下 JavaScript 中的数据类型? 前端面试中,估计大家都被这么问过. 答:Javascript 中的数据类型包括原始类型和引用类型.其中原始类型包括 null.undefined.b ...
- JavaScript 中的数据类型
Javascript中的数据类型有以下几种情况: 基本类型:string,number,boolean 特殊类型:undefined,null 引用类型:Object,Function,Date,Ar ...
随机推荐
- Windows 2003 Server远程代码执行漏洞集合
目录 MS08-067 CVE-2017-7269 MS08-067 发布日期:2008/10/22 针对端口:139.445 漏洞等级:高危 漏洞影响:服务器服务中的漏洞可能允许远程执行代码 受影响 ...
- SQL注入平台(sqli-labs)搭建提示Fatal error: Uncaught Error:
笔者搭建该平台时用的是phpstudy,估计wampserver和xmapp也适用 搭建过程中出现错误 在浏览器进入sqli-labs时有以下提示 Fatal error: Uncaught Erro ...
- 【SpringMVC】添加操作时返回400
本博客老魏原创,如需转载请留言 问题描述: springmvc向数据库添加新的记录时,发生400错误,控制台没有抛出异常. 问题原因: 视图中的提交数据的某一个字段不不匹配导致. 解决方法: 不要怀疑 ...
- C#中的委托(Update)
什么是委托? 委托(delegate)是一种托管方法的数据结构,它是一种引用类型,是对方法的引用.如果说int,string等是对数据类型的定义,那么委托就类似于对"方法类型"的定 ...
- 一款好用的数据血缘关系在线工具--SQLFlow
l 数据血缘关系(data lineage) 数据血缘属于数据治理中的一个概念,是在数据溯源的过程中找到相关数据之间的联系,它是一个逻辑概念.数据治理中经常提到血缘分析,血缘分析是保证数据融合的 ...
- 一个入门级CTF的Reverse
这道题是XCTF攻防世界上的一道新手入门题目! 年前刚接触逆向时IDA,OD了这些工具都不会用(负基础),当时做这些题的时候觉得挺难(主要是缺少练习,没思路无从下手).现在回头再来看这些题目感觉确实是 ...
- python爬虫——《英雄联盟》英雄及皮肤图片
还记得那些年一起网吧开黑通宵的日子吗?<英雄联盟>绝对是大学时期的风靡游戏,即使毕业多年的大学同学相聚,难免不怀念一番当时一起玩<英雄联盟>的日子. 今天就给大家分享一下英雄及 ...
- .NetCore·集成Ocelot组件之完全解决方案
阅文时长 | 11.04分钟 字数统计 | 17672.8字符 主要内容 | 1.前言.环境说明.预备知识 2.Ocelot基本使用 3.Ocelot功能挖掘 4.Ocelot集成其他组件 5.避坑指 ...
- [bug] CM / CDH 主机运行状态不良情况
参考 https://blog.csdn.net/fhfkv8644/article/details/82383196 无法发出查询:Host Monitor 未运行 https://blog.csd ...
- linux操作系统故障处理-ext4文件系统超级块损坏修复
linux操作系统故障处理-ext4文件系统超级块损坏修复 背景 前天外面出差大数据测试环境平台有7台服务器挂了,同事重启好了五台服务器,但是还有两台服务器启动不起来,第二天回来后我和同事再次去机 ...