【javascript】数据精度丢失问题

一、为什么会出现精度丢失的问题

JavaScript中存在小数点精度丢失的问题是由于其使用的浮点数表示方式。JavaScript采用的是双精度浮点数表示法,也称为IEEE 754标准,它使用64位来表示一个数字,其中52位用于表示有效数字,而其他位用于表示符号、指数和特殊情况。

由于使用有限的位数来表示无限的小数,JavaScript无法准确地表示某些小数。其中一个典型的示例是0.1,它在二进制中是一个无限循环的小数。当我们将0.1这样的小数转换为二进制进行存储时,存在近似表示的误差,因此在进行计算时会出现精度丢失的问题。
例如,执行以下计算:

0.1 + 0.2 = 0.30000000000000004

预期的结果应该是0.3,但在JavaScript中实际得到的结果是0.30000000000000004。这是因为0.1和0.2无法以精确的二进制形式表示,导致小数点精度丢失。

这种精度丢失是浮点数表示法的固有特性,并不仅限于JavaScript,其他编程语言也可能面临类似的问题。因此,在进行精确计算时,特别是涉及到货币、金融等方面的计算,应使用其它精确计算的方法,例如使用整数进行运算或使用专门的精确计算库。

总而言之,小数点精度丢失的问题是由于JavaScript使用的浮点数表示法的特性所致,需要在开发中注意,并考虑使用其他方法或工具来解决精度问题。

二、解决方案

1、使用整数进行计算

尽可能地将浮点数转换为整数进行计算。例如,通过将小数位数乘以一个固定的倍数,将浮点数转换为整数,进行计算后再将结果转换回浮点数。这可以减少浮点数计算中的精度问题。

2.使用专门的库或工具

big.js、bignumber.js 和 decimal.js

三、 big.js、bignumber.js 和 decimal.js 的区别

1.包的大小
big.js < bignumber.js < decimal.js
big.js 是最小的任意精度的计算库。big.js 是三者中最小也最简单的,它只有 bignumber.js 一半的方法,不到 bignumber.js 的一半大。
2.功能
1、big.js
  精度采用小数位;精度仅适用除法;4种舍入模式。
2、bignumber.js
  配置选项;NaN;Infinity;精度采用小数位;精度仅适用于除法;随机数字;进制转换;9种舍入模式;模模式;模幂运算。
3、decimal.js
  配置选项;NaN;Infinity;非整数次幂,exp,ln,log;三角函数;精度采用有效数字;所有操作均采取精度;随机数字;9种舍入模式;模模式;二进制,八进制,十六进制;二进制指数符号。

    big.js、bignumber.js 和 decimal.js,这三个库都包含了 JavaScript 中 Number 类型的 toExponential、toFixed 和 toPrecision 方法。

3.性能
bignumber.js 和 decimal.js 存储值的进制比 big.js 更高,因此当操作大量数字时,前两者的速度会更快。

4.使用场景
1、bignumber.js
  适合金融类应用,因为用户不用担心丢失精度,除非使用了涉及除法的操作。
2、decimal.js
  适合科学类应用,因为它可以更有效的处理非常小或者非常大的数值。
  例如,它没有 bignumber.js 的限制,即当将一个小指数值和一个大指数值相加时,bignumber.js 将使用完全精度来操作,这可能使得消耗很多时间。

5.进制
bignumber.js 和 decimal.js 也支持其它进制的计算,并支持前缀,比如十六进制的 0x。decimal.js 还可以使用二进制指数表示法处理二进制、八进制和十六进制,C 语言中就是如此。

bignumber.js处理十六进制:

var x = new BigNumber(‘ff.8’, 16);
x.toString(); // ‘255.5’
x.toString(16); // ‘ff.8’
decimal处理八进制、十六进制:

var x = new Decimal(‘0xff.8’);
x.toString(); // ‘255.5’
x.toHexadecimal(); // ‘0xff.8’
x.toHex(3); // ‘0x1.ffp+7’
3、big.js
big.js 中,NAN 或者 Infinity 是不合法值,它不能处理除了十进制以外的其它进制。

    big.js运行时的配置项仅限于设置小数位数、包含除法在内的四舍五入的运算模式,以及 toString 生成的科学计数法的指数值。

Big.DP = 7; // 最大小数位数
Big.RM = 4; // round half-up
var x = new Big(5);
x.div(3).toString(); // ‘1.6666667’
bignumber.js与decimal.js

    decimal.js 最初是通过向 bignumber.js 添加对非整数次幂的支持来开发的,但后续作者决定将它作为一个单独的库来发布。

    decimal.js和bignumber.js的最主要的区别在于:decimal.js 的精度是以有效数字而不是小数位数来指定的,并且所有的计算都舍入到该精度(类似于 Python 的小数模块),而不是只有涉及到除法的运算。

bignumber.js的精度配置

Bignumber.config({ DECIMAL_PLACES: 3, ROUNDING_MODE; 1 });
var x = new BigNumber(‘123.456789’);
x.plus(1).toString(); // ‘124.456789’
decimal.js的精度配置

Decimal.set({ precision: 7, rounding: 4 });
var y = new Decimal(‘123.456789’);
y.plus(1).toString(); // ‘124.4568’
decimal.js 还支持非整数次幂、三角函数、exp、ln、log 方法。这些额外的方法使得 decimal.js 比 bignumber.js 大得多。

四、decimal.js简单使用

decimal.js API

安装

npm install decimal.js
import {Decimal} from 'decimal.js'; //引用

 const a = 0.1;
 const b = 0.2;
 
 // 加法
 let c = new Decimal(a).add(new Decimal(b)) 
 
 // 减法
 let d = new Decimal(a).sub(new Decimal(b))
 
 // 乘法
 let e = new Decimal(a).mul(new Decimal(b))
    
 // 除法
 let f = new Decimal(a).div(new Decimal(b))

五、参考

https://juejin.cn/post/6844903620140335112

你可能感兴趣的:(js,javascript,开发语言)