|

JavaScript 精度运算必备:big.js 使用详解与实战教程

为什么需要 big.js?

JavaScript 的原生 Number 类型基于 IEEE-754 双精度浮点数,它在处理小数运算时经常会产生精度误差,例如:

0.1 + 0.2  // 结果并不是 0.3,而是 0.30000000000000004

这种误差在涉及金钱、科学计算、统计分析等场景中可能会导致严重后果。big.js 是一个专注于十进制 任意精度 运算的轻量级库,它用字符串或十进制内部表示来避免浮点误差,提供高精度且稳定的算术操作。

big.js 的设计简洁、单一目标,不支持 NaN 或 Infinity,也没有过多的进阶功能,专注在十进制加、减、乘、除、幂与比较等核心功能上。

安装与引入方式

1. 使用 npm / yarn 安装

在 Node.js 或前端构建环境中,可以通过 npm 安装:

npm install big.js

或者使用 yarn:

yarn add big.js

然后在代码中引用:

import Big from 'big.js';
// 或者在 CommonJS 中
const Big = require('big.js');

2. 浏览器引入

若你在页面上直接使用,可以下载 big.min.js 并在 HTML 中通过 script 引入:

<script src="path/to/big.min.js"></script>
<script>
  const x = new Big('1.23');
  console.log(x.plus(0.77).toString());  // "2.00"
</script>

这样可以在全局访问 Big 构造器。

核心概念与全局设置

Big 构造器

Big(n) 或 new Big(n) 用于创建一个大数对象,其中 n 可以是数字、字符串或另一个 Big 对象。若将原生数字传入,则内部会转换为字符串再解析,以避免初始精度损失。

const a = new Big('0.1');
const b = Big(0.2);
const c = new Big(a);  // 复制一个新的 Big

精度(DP)和舍入模式(RM)

  • Big.DP:控制除法、开方、负指数幂运算结果的小数位数(默认通常是 20 位)
  • Big.RM:舍入模式,可选值有 0(向零截断)、1(四舍五入)、2(银行家舍入 / 最近偶数)、3(向远舍入)

你可以按需设置:

Big.DP = 30;      // 设置最多保留 30 位小数
Big.RM = Big.roundHalfUp;  // 使用四舍五入模式

这些设置只在需要舍入的运算(像除法、开方或负幂)中生效。

基本算术操作:加减乘除与幂运算

big.js 的算术方法都是不可变的(immutable),也就是说每次方法调用都会返回一个新的 Big 实例。

1. 加法与减法

const x = Big('1.234');
const y = Big('2.345');

const sum = x.plus(y);       // “3.579”
const diff = x.minus(y);     // “-1.111”

2. 乘法

const prod = x.times(y);

3. 除法

const quotient = x.div(y);

如果除不尽,则结果会根据 Big.DP 与 Big.RM 设置自动舍入。

4. 幂运算(pow)

pow 用于求幂,支持整数幂和负指数幂:

const p1 = Big('0.9').pow(3);    // 0.9 的三次方
const p2 = Big('2').pow(-2);     // 2 的负二次方(即 1/4)

对于负指数幂计算,若结果为小数,则同样受 Big.DP 与 Big.RM 控制。

5. 额外方法:sqrt、abs、mod、neg

  • sqrt():计算平方根
  • abs():取绝对值
  • mod(n):取模运算
  • neg():取相反数

例如:

const z = Big('9').sqrt();   // “3”
const m = Big('10').mod('3');  // “1”
const neg = Big('-5').neg();   // “5”

比较与格式化输出

比较方法

Big 实例提供丰富的比较方法:

  • eq(n):等于
  • gt(n):大于
  • gte(n):大于等于
  • lt(n):小于
  • lte(n):小于等于
  • cmp(n):返回 -1 / 0 / 1

例如:

x.eq('1.234');        // true / false
x.gt(y);              // boolean
x.cmp(y);             // -1 / 0 / 1

输出与格式化

常用输出方法包括:

  • toString():返回标准字符串形式
  • toFixed(dp):保留 dp 位小数,四舍五入
  • toExponential(dp):以指数形式输出
  • toPrecision(sd):按有效位数输出
  • toNumber():将 Big 转为普通 Number(若精度丢失则可能报错,尤其在 strict 模式下不可用)

例如:

const a = Big('2.5');
a.toFixed(5);         // "2.50000"
a.toExponential(2);   // "2.50e+0"
a.toPrecision(3);     // "2.50"
a.toNumber();          // 2.5 (若精度可安全转换)

复杂表达式写法与链式操作

在复杂表达式中,可以采用链式调用或局部拆分写法。举个例子,比如你要计算:

res = a + (b / c) + (d + 1) / (e * f * g)

在 big.js 中可以写为:

const A = Big(a);
const B = Big(b);
const C = Big(c);
const D = Big(d);
const E = Big(e);
const F = Big(f);
const G = Big(g);

const result = A
  .plus(B.div(C))
  .plus(D.plus(1).div(E.times(F).times(G)));

const asNumber = result.toNumber();  // 如果你需要普通数字

你也可以拆解为多个中间变量,但链式写法更加紧凑。

注意事项与最佳实践

  • 避免直接使用原生 Number 参与运算:务必将常量或变量转换为 Big 对象,以免初始就产生精度误差。
  • 慎用 toNumber():它会将高精度 Big 转回普通数字,可能丢失精度;在严格模式下若损失明显可能抛错。
  • 合理设置 DP 与 RM:不要设置过大或过小的小数位数,要根据具体业务场景决定精度上限与舍入方式。
  • 链式调用注意顺序:运算顺序影响最终的舍入结果,建议从最内层先计算,逐步构造链式结构。
  • 性能考量:big.js 并不适合极端大数或大规模运算场景,若你需要更多数学功能(如三角函数、对数、指数),你可能需要更全面的高精度库(如 decimal.js)。
  • 不支持 NaN / Infinity:big.js 的设计理念是严格控制运算范围,不接受不合法数值。
  • 子构造器功能:你可以用 const Big2 = Big() 创建一个新的构造器,该构造器可以有不同的 DP / RM 设置,以满足不同子模块的需求。

总结与应用建议

通过本文,你已经掌握了 big.js 的安装、基本用法、核心设置、比较与格式化、复杂表达式处理以及注意事项。借助 big.js,你可以在 JavaScript 中有效避免浮点误差,在涉及金钱计算、科学数据处理等领域获得更可靠的精度表现。

评论