「前端开发 · 实践分享」4 种方式带你使用 JavaScript 实现高精度计算

916 阅读5分钟

🙏废话不多说系列,直接开整🙏

业务背景:有时候需要前端实时计算出高精度的数据用来快速给客户显示。

这里本文介绍常见的四种方式供大家参考学习:

  1. math.js
  2. bignumber.js
  3. decimal.js
  4. big.js

这 4 种都是可以满足前端高精度计算的需求的,大家不妨根据自己的实际情况使用。


一、mathJS

官网地址:math.js | an extensive math library for JavaScript and Node.js (mathjs.org)

(1)使用示例
<!DOCTYPE html>
<html>
<head>
  <meta name="description" content="math.js | basic usage">
  <title>math.js | basic usage</title>
  <!-- CDN 实现高精度计算 -->
  <!-- 在线 HTML 编辑器地址:https://jsbin.com/devacu/edit?html,output -->
  <script src="https://unpkg.com/mathjs/lib/browser/math.js"></script>
</head>
<body>
  <script>
    // basic usage of math.js
    //
    // website:  http://mathjs.org
    // docs:     http://mathjs.org/docs
    // examples: http://mathjs.org/examples
    
    // functions and constants
    print(math.round(math.e, 3));                // 2.718
    print(math.atan2(3, -3) / math.pi);          // 0.75
    print(math.log(10000, 10));                  // 4
    print(math.sqrt(-4));                        // 2i
    print(math.pow([[-1, 2], [3, 1]], 2));       // [[7, 0], [0, 7]]
    print(math.derivative('x^2 + x', 'x'));      // 2 * x + 1
    
    // expressions
    print(math.evaluate('12 / (2.3 + 0.7)'));    // 4
    print(math.evaluate('12.7 cm to inch'));     // 5 inch
    print(math.evaluate('9 / 3 + 2i'));          // 3 + 2i
    print(math.evaluate('det([-1, 2; 3, 1])'));  // -7
	
	print(math.evaluate('10 / 3'));				// 3.3333333333333
	print(math.evaluate('1 - 0.9'));			// 0.1
	print(math.evaluate('1 - 0.9 * (23 / 2)'));	// -9.35
    
    // chaining
    var a = math.chain(3)
        .add(4)
        .multiply(2)
        .done();
    print(a); // 14
    
    // helper function to output formatted results.
    function print(value) {
      var precision = 14;
      document.write(math.format(value, precision) + '<br>');
    }
  </script>
</body>
</html>
(2)结果展示
2.718
0.75
4
2i
[[7, 0], [0, 7]]
2 * x + 1
4
5 inch
3 + 2i
-7
3.3333333333333
0.1
-9.35
14

二、bignemberJS

官网地址:GitHub - MikeMcl/decimal.js: An arbitrary-precision Decimal type for JavaScript

(1)使用示例
<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>JavaScript 精确计算 - bignemberJS</title>
		<title>Bignumber.js CDN Example</title>
		<!-- 引入 bignumber.js CDN -->
		<script src="https://cdn.jsdelivr.net/npm/bignumber.js@latest/bignumber.min.js"></script>
	</head>
	<body>
		<h1>Bignumber.js CDN 示例</h1>
		<p>计算结果将显示在这里:</p>
		<div id="result"></div>

		<!-- 你的脚本 -->
		<script>
			// 使用 bignumber.js 进行计算  
			let result = new BigNumber(0.1).plus(0.2).toString();

			// 将结果显示在页面上  
			document.getElementById('result').innerText = '0.1 + 0.2 = ' + result;

			// 你可以添加更多的计算示例  
			let result2 = new BigNumber(123.456).times(100).toString();
			document.getElementById('result').innerHTML += '<br>123.456 * 100 = ' + result2;

			let result3 = new BigNumber(335).div(6).dp(3).toString();
			document.getElementById('result').innerHTML += '<br>335 / 6 = ' + result3;
			
			
			
			// 1. 计算 0.1 + 0.2  
			let result4 = new BigNumber(0.1).plus(0.2).toString();  
			console.log('0.1 + 0.2 =', result4); // 输出: 0.3  
			  
			// 2. 计算 123.456 乘以 100  
			let result5 = new BigNumber(123.456).times(100).toString();  
			console.log('123.456 * 100 =', result5); // 输出: 12345.6  
			  
			// 3. 计算 335 除以 6,并保留 3 位小数  
			let result6 = new BigNumber(335).div(6).dp(3).toString();  
			console.log('335 / 6 =', result6); // 输出: 55.833  
			  
			// 也可以直接使用字符串来避免精度问题  
			let result7 = new BigNumber('0.1').plus('0.2').toString();  
			console.log('0.1 (string) + 0.2 (string) =', result7); // 输出: 0.3

		</script>
	</body>
</html>
(2)结果展示
0.1 + 0.2 = 0.3
123.456 * 100 = 12345.6
335 / 6 = 55.833
0.1 (string) + 0.2 (string) = 0.3

image.png

(3)注意事项
  • 在使用 bignumber.js 时,尽量使用字符串来初始化 BigNumber 对象,特别是当数字非常大或精度非常高时。这是因为直接使用数字字面量可能会导致 JavaScript 在解析时就丢失精度。
  • dp 方法用于设置小数点后的位数,并返回一个新的 BigNumber 对象。如果你需要将其转换为字符串或其他类型,可以使用 toString() 方法。
  • bignumber.js 提供了丰富的 API,包括加法、减法、乘法、除法、指数运算、开平方等,可以满足大多数高精度计算的需求。

三、decimalJS

这里为了快速使用 decimal.js 进行计算演示,使用 CDN : 

(1)使用示例
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8" />
        <title>JavaScript 精确计算 - decimalJS</title>
        <!-- CDN -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.3.1/decimal.min.js"></script>
    </head>
    <body>
        <script>
            // 使用 Decimal 构造函数创建一个 Decimal 类型的实例  
            let a = new Decimal(0.1);  
            let b = new Decimal(0.2);

            // 加法  
            let sum = a.plus(b); // 0.3  
            console.log("和:", sum.toString());

            // 减法  
            let diff = a.minus(b); // -0.1  
            console.log("差:", diff.toString())
            // 乘法  
            let product = a.times(b); // 0.02  
            console.log("积:", product.toString())

            // 除法  
            let quotient = a.dividedBy(b); // 0.5  
            console.log("除:", quotient.toString())

            // 也可以链式调用  
            let result = new Decimal(10).times(3).plus(2).dividedBy(4); // 8
            console.log("综合调用:", result.toString())

            Decimal.set({ precision: 5 })  
            let rounded = new Decimal(1).div(3); // 0.33333
            console.log("设置计算精度有效位数:", rounded.toString())
        </script>
    </body>
</html>
(2)结果展示
和: 0.3
差: -0.1
积: 0.02
除: 0.5
综合调用: 8
设置计算精度有效位数: 0.33333
(3)注意事项
  • 当你使用 decimal.js 时,应该总是通过 Decimal 构造函数来创建新的 Decimal 实例,而不是直接使用 JavaScript 原生的数字类型进行运算。
  • decimal.js 提供的 API 大多是以方法的形式存在的,比如 plus()minus()times()dividedBy() 等,这有助于避免原生 JavaScript 中的精度问题。
  • decimal.js 还支持比较、四舍五入、开方、对数等更多高级数学功能。

通过使用 decimal.js,你可以在 JavaScript 中进行高精度的数学计算,而不必担心浮点数运算中常见的精度问题。

四、bigJS

官网地址:GitHub - favio41/big-js: A small, fast JavaScript library for arbitrary-precision decimal arithmetic.

(1)使用示例
// CDN 引入方式一
<script src="https://cdn.jsdelivr.net/npm/big.js@6.0.0/big.min.js" type="text/javascript" charset="utf-8"></script>

// CDN引入方式二
<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/big.js/6.0.3/big.min.js" type="application/javascript"></script>
(2)完整代码展示
<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title></title>
		<script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/big.js/6.0.3/big.min.js"
			type="application/javascript"></script>
		<!-- <script src="https://cdn.jsdelivr.net/npm/big.js@6.0.0/big.min.js" type="text/javascript" charset="utf-8"></script> -->
	</head>
	<body>
		<hr>
	</body>
	<script>
		/**
		 * 加法:四舍五入保留4位有效数据
		 */
		function func_add(a = 0, b = 0, scale = 4) {
			return new Big(a).add(b).toFixed(scale);
		}

		/**
		 * 减法:四舍五入保留4位有效数据
		 */
		function func_sub(a, b, scale = 4) {
			return new Big(a).sub(b).toFixed(scale)
		}

		/**
		 * 乘法:四舍五入保留4位有效数据
		 */
		function func_mul(a = 0, b = 0, scale = 4) {
			return new Big(a).mul(b).toFixed(scale);
		}

		/**
		 * 除法:四舍五入保留4位有效数据
		 */
		function func_div(a, b, scale = 4) {
			try {
				return new Big(a).div(b).toFixed(scale);
			} catch (e) {
				//TODO handle the exception
				// console.error(e)
				return new Big(0).toFixed(scale)
			}
		}

		function func_math() {
			Big.DP = 10
			Big.RM = 1

			x = new Big(2);
			y = new Big(3);
			z = x.div(y) // "0.6666666667"
			z1 = z.sqrt() // "0.8164965809"
			z2 = z.pow(-3) // "3.3749999995"
			z3 = z.times(z) // "0.44444444448888888889"
			z4 = z.times(z).round(10) // "0.4444444445"
			console.log(z1.toFixed(10), z2.toFixed(10), z3.toFixed(10), z4.toFixed(10));
		}


		function fun_initBigDemo() {
			var x = new Big(255.5)
			console.log("位数补齐(指定有效位数为5位):", x.toFixed(5)); // 255.50000
			console.log("科学技术法:", x.toExponential(5)); // 2.55500e+2
			console.log("有效位数:", x.toPrecision(5)); //  255.50
			console.log("定义大数据:", x); // 全部数据结构

			console.log("高精度加法:", func_add(0.111, 0.2122235));
			console.log("高精度减法:", func_sub(1, 0.9, 4));
			console.log("高精度乘法:", func_mul(0.3333, 0.2222222, 6));
			console.log("高精度除法:", func_div(10, 3, 4), func_div(10, 0));
		}

		// fun_initBigDemo(); // 初始化执行此函数
		func_math();
	</script>
</html>

附录


🙏至此,非常感谢阅读🙏