资讯专栏INFORMATION COLUMN

如何解决0.1 +0.2===0.30000000000000004类问题

yuanzhanghu / 1013人阅读

摘要:方法使用定点表示法来格式化一个数,会对结果进行四舍五入。该数值在必要时进行四舍五入,另外在必要时会用来填充小数部分,以便小数部分有指定的位数。如果数值大于,该方法会简单调用并返回一个指数记数法格式的字符串。在环境中,只能是之间,测试版本为。

上篇博客深度剖析了0.1+0.2 === 0.30000000000000004的原因。
这篇博客将主要提供几种解决小数精度丢失问题的Javascript类库的代码示例,以及简单的原生EcmaScript方法的代码示例。

一.类库部分 math.js

math.js是JavaScript和Node.js的一个广泛的数学库。支持数字,大数,复数,分数,单位和矩阵等数据类型的运算。

官网:http://mathjs.org/
GitHub:https://github.com/josdejong/mathjs

0.1+0.2 ===0.3实现代码:

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"
decimal.js

为 JavaScript 提供十进制类型的任意精度数值。

官网: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"
bignumber.js

用于任意精度算术的JavaScript库。

官网:http://mikemcl.github.io/bignumber.js/

Github:https://github.com/MikeMcl/bignumber.js

var BigNumber = require("bignumber.js")
x = new BigNumber(0.1)
y = 0.2
console.log(x.plus(y).toString())//"0.3"
big.js

用于任意精度十进制算术的小型快速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...

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/89610.html

相关文章

  • JS魔法堂:彻底理解0.1 + 0.2 === 0.30000000000000004的背后

    摘要:也就是说不仅是会产生这种问题,只要是采用的浮点数编码方式来表示浮点数时,则会产生这类问题。到这里我们都理解只要采取的浮点数编码的语言均会出现上述问题,只是它们的标准类库已经为我们提供了解决方案而已。 Brief 一天有个朋友问我JS中计算0.7 * 180怎么会等于125.99999999998,坑也太多了吧!那时我猜测是二进制表示数值时发生round-off error所导致,但并不...

    JerryWangSAP 评论0 收藏0
  • 探寻 JavaScript 精度问题以及解决方案

    摘要:推导为何等于在中所有数值都以标准的双精度浮点数进行存储的。先来了解下标准下的双精度浮点数。精度位总共是,因为用科学计数法表示,所以首位固定的就没有占用空间。验证完成的最大安全数是如何来的根据双精度浮点数的构成,精度位数是。 阅读完本文可以了解到 0.1 + 0.2 为什么等于 0.30000000000000004 以及 JavaScript 中最大安全数是如何来的。 十进制小数转为二...

    YanceyOfficial 评论0 收藏0
  • JS中如何理解浮点数?

    摘要:本文通过介绍的二进制存储标准来理解浮点数运算精度问题,和理解对象的等属性值是如何取值的,最后介绍了一些常用的浮点数精度运算解决方案。浮点数精度运算解决方案关于浮点数运算精度丢失的问题,不同场景可以有不同的解决方案。 本文由云+社区发表 相信大家在平常的 JavaScript 开发中,都有遇到过浮点数运算精度误差的问题,比如 console.log(0.1+0.2===0.3)// fa...

    bang590 评论0 收藏0
  • 深度剖析0.1 +0.2===0.30000000000000004的原因

    摘要:吐槽一句,大二的专业课数字逻辑电路终于用在工作上了。,整数位为,且精度只到十分位,因此是。如果是不限精度的话,转换后的二进制数应该是无限循环。再看一下百科给出的标准因此,的类型,最高的位是符号位,接着的位是指数,剩下的位为有效数字。 showImg(https://segmentfault.com/img/remote/1460000011902479?w=600&h=600); 用一...

    haobowd 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<