Handling precision issues in JavaScript numerical calculations

js precision problem

When using JavaScript to perform numerical calculations, you face some precision issues that can lead to incorrect results. The following are some common and weird js data accuracy issues:

1. Floating point precision problem

In JS, floating point numbers have limited precision. For example:

0.1 + 0.2 // 结果为0.30000000000000004
23.327*100 // 结果为2332.7000000000003

This result obviously does not meet our expectations. Because this is because floating point numbers themselves cannot represent the exact values ​​of 0.1 and 0.2.

Solution: You can toFixedconvert it to a string preserving a specific number of decimal places using the method, or use Bigthe object from the Big.js library.

2. Integer operation out of range

In JS, the range of integer operations is -2^53 ~ 2^53. When the operation result exceeds this range, strange things will happen, such as:

Math.pow(2, 53) + 1 // 结果为9007199254740992

Solution: You can use the BigInt type to perform a wider range of integer operations, but please note that the support is not widespread enough and additional support is required in the browser and Node.js environment.

3. Numeric type conversion problem

Converting between numeric types can also cause strange problems in JS. For example:

"10" > "9" // 结果为false

The reason is that in string comparison, the character encoding is compared instead of the actual number size.

Solution: You can use parseIntor parseFloatto convert a string to a number, or use Numberthe function to cast a string to a number.

4. Extra zeros after the decimal point

In JS, when converting a decimal to a string, if it does not have a decimal part, it will be added by default .0. For example:

String(1.0) // 结果为"1.0"

This automatic addition of decimal points may cause the output to be inconsistent with expectations.

Solution: You can use Number.prototype.toFixed()to maintain a certain number of decimal places, or use Number.prototype.toPrecision()to control the total number of decimal places.

Big.js

Big.js is a JavaScript "arbitrary precision" number library that can handle large number calculations that cannot be represented by ordinary numbers. This library can be very useful, for example, in financial trading, cryptography, and scientific computing.

Install

Big.js can be installed in a variety of ways:

  • npm installation:npm install big.js
  • Download the source code package: https://github.com/MikeMcl/big.js/archive/v5.2.2.tar.gz
  • Online CDN introduction: <script src="https://cdn.jsdelivr.net/npm/[email protected]/big.min.js"></script>(jsDelivr CDN is used here)

Instructions

Introduce big.js into the code:

const Big = require('big.js');

Create a Big object

const x = new Big(123.4567);
const y = Big(987654321.123456789);
const z = new Big('123456789012345678901234567890');

The above code creates three Big objects. You can pass any string, number, or other Big object to the constructor. Note that only strings can correctly represent decimals such as 0.1, 0.01, etc. We can print the values ​​of these objects in the following way:

console.log(x.toString()); // "123.4567"
console.log(y.toString()); // "987654321.123456789"
console.log(z.toString()); // "123456789012345678901234567890"

perform calculations

Big.js supports +, -, *, /, mod, pow, sqrt and abs operations. Here is the code example:

const x = Big(123.4567);
const y = Big('987654321.123456789');

console.log(x.plus(y).toString());    // "987654444.580156789"
console.log(x.minus(y).toString());   // "-987654197.666756789"
console.log(x.times(y).toString());   // "121931366283.89509775303"
console.log(x.div(y).toString());     // "0.00012468606749151914"
console.log(x.mod(y).toString());     // "123.4567"
console.log(x.pow(3).toString());     // "18604128.120667185023"
console.log(x.sqrt().toString());     // "11.107774091203273684"
console.log(x.abs().toString());      // "123.4567"

Set operation precision

By default, Big.js rounds results to 20 digits. But you can change this precision setting. Two methods are provided here:

Global configuration

Globally, you can change the default settings through Big.RM and Big.DP. RP (Rounding Precision) specifies the rounding precision (default is 20), while DP (Decimal Places) specifies the number of decimal places retained by default.

Big.RM = 0; // 舍去模式(0 表示四舍五入)
Big.DP = 10; // 小数点后保留 10 位
local configuration

If you don't want to change the settings globally, you can set them individually for each operation. Here's how to use them:

const x = new Big(1);
const y = new Big(3);

x.div(y);            // '0.33333333333333333333'
x.dp = 2;            // 将小数点后的位数设置为 2
x.div(y);            // '0.33'
x.round(1);          // 四舍五入至整数
x.div(y).toString(); // '0.3'

Hexadecimal and binary formats

Numbers in hexadecimal and binary formats are particularly important when dealing with special data types such as cryptographic hashes. Fortunately, Big.js provides related methods. Here are relevant code examples:

Creating a big.js instance requires passing in a number or string. Here is an example of creating a big.js instance:

const num1 = new Big(123.4567);
const num2 = new Big("9876543210123456789");

addition

Big objects can use plus()the method to perform addition operations, returning a new Big object without changing the original object:

const num1 = new Big(1.23);
const num2 = new Big(4.56);

const result = num1.plus(num2); // 等价于 num1 + num2
console.log(result.toString()); // 5.79

Subtraction

Big objects can use minus()the method to perform subtraction operations, returning a new Big object without changing the original object:

const num1 = new Big(1.23);
const num2 = new Big(4.56);

const result = num1.minus(num2); // 等价于 num1 - num2
console.log(result.toString()); // -3.33

multiplication

Big objects can use times()the method to perform multiplication operations, returning a new Big object without changing the original object:

const num1 = new Big(1.23);
const num2 = new Big(4.56);

const result = num1.times(num2); // 等价于 num1 * num2
console.log(result.toString()); // 5.6088

division

Big objects can use div()the method to perform division operations, returning a new Big object without changing the original object:

const num1 = new Big(1.23);
const num2 = new Big(4.56);

const result = num1.div(num2); // 等价于 num1 / num2
console.log(result.toString()); // 0.26973684210526315789

Exponentiation

Big objects can use pow()the method to perform exponentiation operations, returning a new Big object without changing the original object:

const num1 = new Big(2);
const num2 = new Big(3);

const result = num1.pow(num2); // 等价于 num1 ** num2
console.log(result.toString()); // 8

Compare

Big objects can use cmp()the method to perform comparison operations, returning a negative, zero, or positive number, indicating less than, equal to, or greater than, respectively.

const num1 = new Big(1.23);
const num2 = new Big(4.56);

console.log(num1.cmp(num2)); // -1
console.log(num2.cmp(num1)); // 1
console.log(num1.cmp(num1)); // 0

Rounding and decimal places

Big objects can use toFixed()methods to perform rounding and decimal-preservation operations:

const num1 = new Big(1.23456789);

console.log(num1.toFixed(2)); // 1.23
console.log(num1.toFixed(5)); // 1.23457
console.log(num1.toFixed(10)); // 1.2345678900

When dealing with large values, using a high-precision library like big.js can avoid the precision problem of the Number type in JavaScript.

Guess you like

Origin blog.csdn.net/lin5165352/article/details/132567775