前端如何應對精確數字運算?用BigNumber.js解決JavaScript原生Number類型在處理大數或高精度計算時的局限性
一、BigNumber.js介紹
1、什么是 BigNumber.js?
BigNumber.js 是一個 JavaScript 庫,用于處理高精度的數字運算。它解決了 JavaScript 原生 Number 類型在處理大數或高精度計算時的局限性。由于 JavaScript 的 Number 類型基于 IEEE 754 標準(雙精度浮點數),其精度限制為 53 位有效數字,因此在處理大數或需要高精度的場景下容易出現精度丟失的問題。
BigNumber.js專注于十進制精度運算,內部使用字符串進行十進制模擬,完全避免了 JS 的二進制浮點誤差。默認不會丟失精度,也不會四舍五入除非你手動指定。在很多真實應用場景中(如金融、金額、電商)至關重要。
// 精度計算問題
console.log(0.1+0.2); // 0.30000000000000004
// 大數比較問題,超過2^53 - 1 = 9007199254740991的數字會丟失精度
console.log(15615616981519815 === 15615616981519816)
2、作用領域
BigNumber.js 的主要作用領域包括但不限于以下場景:
- 金融計算:貸款利息計算、匯率轉換、交易金額處理等。
- 科學計算:天文學中的距離計算、化學中的分子量計算等。
- 區塊鏈與加密貨幣:比特幣、以太坊等加密貨幣的交易金額等。
- 數據統計與分析:統計報表、數據分析工具等。
- 其他高精度需求場景:游戲開發中的經濟系統(虛擬貨幣)、電子商務中的價格計算等。
3、核心特性
BigNumber.js 的核心特性使其成為處理高精度數字的理想選擇:能支持任意精度;每次操作都會返回一個新的BigNumber對象,不修改原始對象;支持豐富的數學運算;支持多種格式化輸出方式;配置靈活且跨平臺兼容。
二、安裝配置與基礎用法
1、引入 BigNumber.js
通過npm安裝:
npm install bignumber.js
然后在代碼中引入:
const BigNumber = require('bignumber.js');
// 或者(ES6 模塊語法)
import BigNumber from 'bignumber.js';
如果不想使用 npm,可以直接通過 CDN 在 HTML 文件中引入:
<script src="https://cdn.jsdelivr.net/npm/bignumber.js/bignumber.min.js"></script>
<script>
// 使用全局變量 BigNumber
const num = new BigNumber('123456789.123456789');
console.log(num.toString());
</script>
2、配置 BigNumber.js
BigNumber.js 提供了全局配置選項,可以設置默認精度、舍入模式等。這些配置對所有 BigNumber 實例生效。
BigNumber.config({
DECIMAL_PLACES: 10, // 設置小數點后保留位數
ROUNDING_MODE: BigNumber.ROUND_HALF_UP, // 四舍五入
EXPONENTIAL_AT: [-15, 20], // 設置科學計數法的觸發范圍
});
- DECIMAL_PLACES:控制小數點后的保留位數。
- ROUNDING_MODE:定義舍入模式,支持以下選項:
- BigNumber.ROUND_UP:向上取整。
- BigNumber.ROUND_DOWN:向下取整。
- BigNumber.ROUND_HALF_UP:四舍五入。
- BigNumber.ROUND_HALF_DOWN:五舍六入。
- EXPONENTIAL_AT :設置科學計數法的觸發范圍。例如,[-15, 20] 表示當數字小于 1e-15 或大于 1e20 時,會自動轉換為科學計數法。
你也可以在創建 BigNumber 實例時用局部配置代替全局配置:
const num = new BigNumber('1.23456789', { DECIMAL_PLACES: 5 });
console.log(num.toString()); // 輸出:1.23457
3、常用方法
以下是一些常用的 BigNumber.js 方法及其用途:
①創建 BigNumber 實例
const num = new BigNumber('123456789.123456789');
console.log(num.toString()); // 輸出:123456789.123456789
②基本運算
BigNumber.js 支持加法、減法、乘法、除法、取模等操作。
const a = new BigNumber('10');
const b = new BigNumber('3');
console.log(a.plus(b).toString()); // 加法:13
console.log(a.minus(b).toString()); // 減法:7
console.log(a.times(b).toString()); // 乘法:30
console.log(a.div(b).toString()); // 除法:3.3333333333333333333
console.log(a.mod(b).toString()); // 取模:1
③冪運算
const num = new BigNumber('2');
console.log(num.pow(10).toString()); // 冪運算:1024
④絕對值
const num = new BigNumber('-123.45');
console.log(num.abs().toString()); // 絕對值:123.45
⑤舍入
const num = new BigNumber('1.23456789');
console.log(num.toFixed(2, BigNumber.ROUND_UP)); // 向上取整:1.24
console.log(num.toFixed(2, BigNumber.ROUND_DOWN)); // 向下取整:1.23
console.log(num.toFixed(2, BigNumber.ROUND_HALF_UP)); // 四舍五入:1.23
⑥比較
const a = new BigNumber('10');
const b = new BigNumber('20');
console.log(a.comparedTo(b)); // 比較:-1(a < b)
console.log(a.isEqualTo(b)); // 判斷是否相等:false
console.log(a.isGreaterThan(b)); // 判斷是否大于:false
console.log(a.isLessThan(b)); // 判斷是否小于:true
⑦格式化輸出
const num = new BigNumber('123456789.123456789');
console.log(num.toString()); // 默認格式:123456789.123456789
console.log(num.toFormat(2)); // 格式化為兩位小數:123,456,789.12
console.log(num.toExponential(2)); // 科學計數法:1.23e+8
⑧鏈式調用
const result = new BigNumber('10')
.plus('5') // 10 + 5 = 15
.times('2') // 15 * 2 = 30
.div('3') // 30 / 3 = 10
.pow('2'); // 10^2 = 100
console.log(result.toString()); // 輸出:100
三、核心特性
1、大數精度丟失問題
JavaScript 原生 Number 類型在處理非常大的數字或小數時會出現精度丟失,而 BigNumber.js 能確保任意精度。
// 原生 JavaScript
console.log(9007199254740992 === 9007199254740993); // 輸出:true(錯誤)
// 使用 BigNumber.js
const BigNumber = require('bignumber.js');
const num1 = new BigNumber('9007199254740992');
const num2 = new BigNumber('9007199254740993');
console.log(num1.eq(num2)); // 輸出:false(正確)
2、小數運算精度問題
原生 JavaScript 在處理小數運算時可能會出現浮點數精度誤差,而 BigNumber.js 能確保精確結果。
// 原生 JavaScript
console.log(0.1 + 0.2); // 輸出:0.30000000000000004(錯誤)
// 使用 BigNumber.js
const BigNumber = require('bignumber.js');
const num1 = new BigNumber('0.1');
const num2 = new BigNumber('0.2');
console.log(num1.plus(num2).toString()); // 輸出:0.3(正確)
3、大數乘除法精度問題
原生 JavaScript 在處理大數乘/除法時可能會丟失精度,而 BigNumber.js 能確保精確結果。
// 原生 JavaScript
const weiAmount = 1000000000000000001; // 1 ETH + 1 wei
const ethAmount = weiAmount / 1000000000000000000;
console.log(ethAmount); // 輸出:1.0000000000000002(錯誤)
// 使用 BigNumber.js
const BigNumber = require('bignumber.js');
const weiAmount = new BigNumber('1000000000000000001'); // 1 ETH + 1 wei
const ethAmount = weiAmount.div(new BigNumber('1000000000000000000'));
console.log(ethAmount.toString()); // 輸出:1.000000000000000001(正確)
四、總結
BigNumber.js 是為了解決 JS 在處理“十進制小數”時精度丟失的問題而生的。相比之下,其他庫要么功能更復雜(decimal.js)、要么精度控制不默認(math.js)、要么只處理整數(BigInt)。