上篇博客深度剖析了0.1+0.2 === 0.30000000000000004的缘由。
这篇博客将主要提供几种解决小数精度丢失问题的Javascript类库的代码示例,以及简单的原生EcmaScript方法的代码示例。css
math.js是JavaScript和Node.js的一个普遍的数学库。支持数字,大数,复数,分数,单位和矩阵等数据类型的运算。git
官网:http://mathjs.org/
GitHub:https://github.com/josdejong/mathjsgithub
0.1+0.2 ===0.3实现代码:npm
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'
为 JavaScript 提供十进制类型的任意精度数值。api
官网:http://mikemcl.github.io/decimal.js/浏览器
GitHub:https://github.com/MikeMcl/decimal.js测试
var Decimal = require('decimal.js') x = new Decimal(0.1) y = 0.2 console.log(x.plus(y).toString())//'0.3'
用于任意精度算术的JavaScript库。网站
官网:http://mikemcl.github.io/bignumber.js/ui
Github:https://github.com/MikeMcl/bignumber.jsspa
var BigNumber = require("bignumber.js") x = new BigNumber(0.1) y = 0.2 console.log(x.plus(y).toString())//'0.3'
用于任意精度十进制算术的小型快速JavaScript库。
官网:http://mikemcl.github.io/big.js/
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'
有一个须要注意的点,使用类库此时输出的0.3是String类型,所以若想保持为Number类型,可以使用parseFloat()方法。
还有一个注意点,在本地install测试的时候,npm i mathjs -g ,require是也要require('mathjs'),而不是带点的math.js,由于josdejong这哥们在建立项目的时候就命名为mathjs,而同时拥有上述decimal.js, bignumber.js和big.js的MikeMcl,项目名字就带了dot,所以安装和引入时,都是xxx.js的形式。
如何在这三个类库之间作选择,还须要你们本身根据具体状况具体分析,我在这里就不赘述了。
最后,教你们一个线上直接测试的网站,https://npm.runkit.com,子路径输入想要测试的Node.js package名,就能够实如今线测试包中的api了。
例如:
math.js:https://npm.runkit.com/mathjs
big.js:https://npm.runkit.com/big.js
类库其实很强大,咱们计算0.1+0.2其实只是用到了冰山一角,那么咱们如何使用原生的EcmaScript代码来应用于简单的问题场景呢?
这就要用到Number.prototype.toFixed()这个方法了。
浮点数运算
toFixed() 方法
浮点数运算的解决方案有不少,这里给出一种目前经常使用的解决方案, 在判断浮点数运算结果前对计算结果进行精度缩小,由于在精度缩小的过程总会自动四舍五入。
toFixed() 方法使用定点表示法来格式化一个数,会对结果进行四舍五入。语法为:
JavaScript 代码:
numObj.toFixed(digits)
参数 digits 表示小数点后数字的个数;介于 0 到 20 (包括)之间,实现环境可能支持更大范围。若是忽略该参数,则默认为 0。
返回一个数值的字符串表现形式,不使用指数记数法,而是在小数点后有 digits 位数字。该数值在必要时进行四舍五入,另外在必要时会用 0 来填充小数部分,以便小数部分有指定的位数。 若是数值大于 1e+21,该方法会简单调用 Number.prototype.toString()并返回一个指数记数法格式的字符串。
特别注意:toFixed() 返回一个数值的字符串表现形式。
具体能够查看 MDN中的说明,那么咱们能够这样解决精度问题:
JavaScript 代码:
parseFloat((数学表达式).toFixed(digits)); // toFixed() 精度参数须在 0 与20 之间 // 运行 parseFloat((0.1 + 0.2).toFixed(10))//结果为0.3 parseFloat((0.3 / 0.1).toFixed(10)) // 结果为 3 parseFloat((0.7 * 180).toFixed(10))//结果为126 parseFloat((1.0 - 0.9).toFixed(10)) // 结果为 0.1 parseFloat((9.7 * 100).toFixed(10)) // 结果为 970 parseFloat((2.22 + 0.1).toFixed(10)) // 结果为 2.32
在Browser环境精度参数容许0~100位之间(包括100),测试版本为Chrome62(64位)和Firefox56 (32 位)。
在Nodejs环境中,只能是0~20之间,测试版本为v6.9.5。
其次就是toFixed()的浏览器兼容性讨论,MDN给出的结果所有是YES,不管desktop端仍是mobile端,也就是说不用担忧toFixed()的兼容性问题(ie8- 咱们不作讨论)。
desktop端:
mobile端:
Thanks:
http://www.css88.com/archives...
https://developer.mozilla.org...