在新公司的第一个项目是区块链相关的管理后台和交易所,其中就涉及了很多的计算问题。而JavaScript因为存在计算的精度问题,所以直接计算就可能会导致各种各样的bug,为了解决这个问题,就要使用BigNumber.js这个库。
至于为什么JavaScript会有精度问题呢,可以看这里。简单来说就是因为:JavaScript中所有的数字(包括整数和小数)都只有一种类型–Number。它的实现遵循IEEE 754标准,使用64位固定长度来表示,也就是标准的double双精度浮点数。它的优点是可以归一化处理整数和小数,节省储存空间。而实际计算的时候会转换成二进制计算再转成十进制。进制转换之后会很长,舍去一部分,计算再转回来,就有了精度误差。
BigNumber.js是一个用于任意精度计算的js库。可以在 官方文档 的console中测试使用。也可以通过npm install bignumber.js --save
来安装。然后 import BigNumber from 'bignumber.js'
来引入使用。他的大概原理是将所有数字当做字符串,重新实现了计算逻辑。缺点是性能比原生的差很多。
现在 TC39 已经有一个 Stage 3 的提案 proposal bigint,大数问题有望彻底解决。在浏览器正式支持前,可以使用 Babel 7.0 来实现,它的内部是自动转换成 big-integer 来计算,要注意的是这样能保持精度但运算效率会降低。
具体用法可以参考以下资料:
就不再敖述了,下边随便写点常用的方法:
// 转为 bignumber
const x= new BigNumber('123456789.123456789');
// 转为 普通数字
x.toNumber()
// 格式化(小数点)
x.toFormat() // '123,456,789.123456789'
x.toFormat(3) // '123,456,789.123'
// 计算
x.plus(0.1) // 加法
x.minus(0.1) // 减法
x.times(0.1) // 乘法
x.div(0.1) // 除法
x.mod(3) // 取模/取余
// 比较大小
x.eq(y) // isEqualTo 的简写,是否相等
x.gt(y) // isGreaterThan 的简写,是否大于
x.gte(y) // isGreaterThanOrEqualTo 的简写,是否大于等于
x.lt(y) // isLessThan 的简写,是否小于
x.lte(y) // isLessThanOrEqualTo 的简写,是否小于等于
// 取非,改变数字的正负号
x.negated()