Cách sử dụng số lớn BigInt và JavaScript

Javascript căn bản | by Học Javascript

Trong JavaScript, kiểu dữ liệu Number thường được sử dụng để xử lý các giá trị số. Tuy nhiên, kiểu dữ liệu này có một giới hạn quan trọng: nó chỉ có thể biểu diễn chính xác các số nguyên trong phạm vi ±(2⁵³ - 1) (tức là khoảng ±9,007,199,254,740,991). Khi làm việc với những số lớn hơn, JavaScript có thể làm tròn hoặc mất đi độ chính xác, dẫn đến lỗi tính toán.

Để khắc phục hạn chế này, JavaScript đã giới thiệu BigInt – một kiểu dữ liệu mới cho phép lưu trữ và xử lý các số nguyên có kích thước rất lớn mà không bị giới hạn bởi phạm vi của Number. BigInt giúp đảm bảo độ chính xác khi làm việc với các số lớn, đặc biệt trong các lĩnh vực như mã hóa, tài chính, và xử lý dữ liệu lớn.

Vậy, BigInt hoạt động như thế nào? Cách khai báo và sử dụng nó ra sao? Chúng ta hãy cùng tìm hiểu chi tiết trong bài viết này.

BigInt trong JavaScript là gì?

BigInt là một kiểu dữ liệu mới trong JavaScript được giới thiệu từ ES11 (ECMAScript 2020). Nó cho phép lưu trữ và thực hiện các phép toán với các số nguyên cực lớn mà không bị mất độ chính xác.

Trước đây, kiểu Number trong JavaScript chỉ có thể biểu diễn chính xác các số nguyên trong khoảng -(2⁵³ - 1) đến (2⁵³ - 1) (tức khoảng ±9,007,199,254,740,991). Nếu vượt quá phạm vi này, JavaScript có thể làm tròn hoặc mất độ chính xác. BigInt giúp giải quyết vấn đề này bằng cách lưu trữ số nguyên dưới dạng một kiểu dữ liệu đặc biệt.

Cách khai báo BigInt

Có hai cách để tạo một giá trị BigInt trong JavaScript:

Cách 1: Sử dụng hậu tố n

Khi khai báo một số nguyên với hậu tố n, JavaScript sẽ tự động hiểu đó là kiểu BigInt.

let bigNumber = 123456789012345678901234567890n;
console.log(bigNumber); 
console.log(typeof bigNumber); // "bigint"

Ở đây, số 123456789012345678901234567890 vượt quá phạm vi của kiểu Number, nhưng nhờ n, nó được lưu trữ chính xác dưới dạng BigInt.

Cách 2: Sử dụng hàm BigInt()

Có thể sử dụng hàm BigInt() để chuyển đổi một số hoặc chuỗi thành BigInt.

let fromNumber = BigInt(1234567890123456789);
let fromString = BigInt("987654321098765432109876543210");

console.log(fromNumber);  // 1234567890123456789n
console.log(fromString);  // 987654321098765432109876543210n

Lưu ý:

  • BigInt() chỉ chấp nhận số nguyên hoặc chuỗi số hợp lệ, nếu truyền số thập phân sẽ gây lỗi:
console.log(BigInt(10.5)); // Lỗi: Cannot convert a number with decimals to a BigInt

So sánh BigInt với Number

Đặc điểm Number BigInt
Kích thước tối đa ±(2⁵³ - 1) (~9,007,199,254,740,991) Không giới hạn
Mất độ chính xác với số lớn? Có thể xảy ra Không
Hỗ trợ số thập phân? Không
Hỗ trợ toán tử số học? Có, nhưng không thể kết hợp với Number

Ví dụ về mất độ chính xác của Number:

let num = 9007199254740991; // Giá trị lớn nhất mà Number có thể giữ chính xác
console.log(num + 1); // 9007199254740992
console.log(num + 2); // 9007199254740992 (sai!)

Sử dụng BigInt để khắc phục lỗi này:

let bigNum = 9007199254740991n;
console.log(bigNum + 1n); // 9007199254740992n
console.log(bigNum + 2n); // 9007199254740993n (chính xác!)

Lưu ý: Không thể thực hiện phép toán giữa BigIntNumber trực tiếp, nếu cố gắng sẽ gặp lỗi:

console.log(10n + 5); // Lỗi: Cannot mix BigInt and other types

Cần chuyển đổi kiểu dữ liệu trước khi thực hiện phép toán:

console.log(10n + BigInt(5)); // 15n
console.log(Number(10n) + 5); // 15
BigInt mang lại lợi ích lớn khi làm việc với các số nguyên cực lớn trong các lĩnh vực như mã hóa, tài chính, và xử lý dữ liệu lớn. Tiếp theo, chúng ta sẽ tìm hiểu cách sử dụng BigInt trong các phép toán số học.

Các phép toán với BigInt trong JavaScript

BigInt hỗ trợ hầu hết các phép toán số học giống như kiểu dữ liệu Number. Tuy nhiên, có một số điểm khác biệt quan trọng, đặc biệt là khi làm việc với phép chia và khi kết hợp với kiểu Number.

Các phép toán số học với BigInt

Giống như Number, BigInt hỗ trợ các phép toán cơ bản:

Phép toán Ký hiệu Ví dụ
Cộng + a + b
Trừ - a - b
Nhân * a * b
Chia / a / b (Lưu ý: Luôn làm tròn xuống)
Chia lấy dư % a % b
Lũy thừa ** a ** b

Ví dụ chi tiết về các phép toán số học

Phép cộng (+) và phép trừ (-)

let a = 10000000000000000000n; 
let b = 20000000000000000000n;

console.log(a + b); // 30000000000000000000n
console.log(b - a); // 10000000000000000000n

Phép nhân (*)

let x = 123456789n;
let y = 987654321n;

console.log(x * y); // 121932631112635269n

Phép chia (/) – Lưu ý làm tròn xuống

Trong JavaScript, khi sử dụng phép chia / với Number, kết quả có thể là số thực. Tuy nhiên, với BigInt, phép chia luôn làm tròn xuống (loại bỏ phần thập phân).

console.log(10n / 3n); // 3n (không phải 3.33)
console.log(15n / 4n); // 3n (không phải 3.75)
Lưu ý: Nếu cần kết quả chính xác với số thực, bạn phải chuyển đổi BigInt về Number trước khi chia:
console.log(Number(15n) / 4); // 3.75

Phép chia lấy dư (%)

console.log(10n % 3n); // 1n
console.log(20n % 6n); // 2n

Phép lũy thừa (**)

console.log(2n ** 10n); // 1024n
console.log(5n ** 3n); // 125n

Không thể kết hợp BigInt với Number trực tiếp

Trong JavaScript, bạn không thể thực hiện phép toán giữa BigIntNumber trực tiếp. Nếu cố gắng, bạn sẽ gặp lỗi:

console.log(10n + 5); //  Lỗi: Cannot mix BigInt and other types

Cách khắc phục:

Cách 1: Chuyển Number thành BigInt

console.log(10n + BigInt(5)); // 15n
console.log(20n * BigInt(3)); // 60n

Cách 2: Chuyển BigInt thành Number (nếu giá trị không quá lớn)

console.log(Number(10n) + 5); // 15
console.log(Number(20n) * 3); // 60

Lưu ý: Khi chuyển BigInt sang Number, nếu giá trị quá lớn, có thể bị mất độ chính xác.

Chuyển đổi dữ liệu BigInt trong JavaScript

Làm việc với BigInt trong JavaScript đôi khi đòi hỏi phải chuyển đổi giữa Number, BigInt, hoặc String. Dưới đây là cách thực hiện từng loại chuyển đổi.

Chuyển Number thành BigInt

JavaScript không cho phép thực hiện phép toán trực tiếp giữa NumberBigInt. Do đó, nếu cần sử dụng BigInt, bạn phải chuyển đổi Number thành BigInt bằng cách sử dụng hàm BigInt().

Cú pháp

BigInt(số);
Ví dụ
let num = 12345; // Số kiểu Number
let bigNum = BigInt(num); // Chuyển sang BigInt

console.log(bigNum); // 12345n
console.log(typeof bigNum); // "bigint"

Lưu ý:

  • Bạn không thể chuyển đổi Number dạng số thực (float) sang BigInt.
  • Nếu cố gắng chuyển BigInt(12.34), bạn sẽ gặp lỗi.
console.log(BigInt(12.34)); // Lỗi: Cannot convert a number with decimals to a BigInt

Cách khắc phục: Làm tròn số trước khi chuyển đổi.

console.log(BigInt(Math.floor(12.34))); // 12n

Chuyển BigInt thành Number

Mặc dù BigInt hỗ trợ làm việc với số rất lớn, đôi khi bạn cần chuyển về kiểu Number để thực hiện các phép toán không hỗ trợ BigInt.

Cú pháp

Number(bigint);

Ví dụ

let bigNumber = 9999999999999999999n; // BigInt
let normalNumber = Number(bigNumber); // Chuyển về Number

console.log(normalNumber); // 10000000000000000000
console.log(typeof normalNumber); // "number"

ưu ý:

  • Nếu giá trị BigInt quá lớn, khi chuyển sang Number sẽ bị mất độ chính xác.
  • Number trong JavaScript chỉ hỗ trợ chính xác tối đa 15-17 chữ số.

Ví dụ về mất độ chính xác:

let bigNum = 900719925474099123456789n; // Rất lớn
console.log(Number(bigNum)); // 9.007199254740992e+23 (mất độ chính xác)

Giải pháp: Nếu số quá lớn, nên giữ nguyên BigInt thay vì chuyển sang Number.

Chuyển BigInt thành chuỗi (String)

Nếu bạn cần hiển thị BigInt dưới dạng văn bản, hãy sử dụng .toString().

Cú pháp

bigint.toString();
Ví dụ
let bigIntValue = 12345678901234567890n;
let strValue = bigIntValue.toString(); // Chuyển sang chuỗi

console.log(strValue); // "12345678901234567890"
console.log(typeof strValue); // "string"

Chuyển đổi BigInt thành String khi cần hiển thị trên giao diện web.

Lưu BigInt vào file JSON (vì JSON không hỗ trợ BigInt).

let bigData = 987654321987654321n;
let jsonData = JSON.stringify({ value: bigData.toString() });

console.log(jsonData); // {"value":"987654321987654321"}

Các lỗi thường gặp khi làm việc với BigInt trong JavaScript

Mặc dù BigInt rất hữu ích khi làm việc với số lớn, nhưng nó cũng có một số giới hạnlỗi phổ biến cần lưu ý. Dưới đây là các lỗi thường gặp và cách khắc phục khi sử dụng BigInt trong JavaScript.

Lỗi khi cố gắng kết hợp BigInt với Number

JavaScript không cho phép thực hiện phép toán giữa BigIntNumber trực tiếp. Nếu cố gắng làm vậy, chương trình sẽ báo lỗi TypeError.

Ví dụ lỗi

let bigNum = 100n; // BigInt
let normalNum = 10; // Number

console.log(bigNum + normalNum); //  TypeError: Cannot mix BigInt and other types

Cách khắc phục

Bạn có hai cách để giải quyết vấn đề này:

Cách 1: Chuyển Number thành BigInt trước khi thực hiện phép toán

let result = bigNum + BigInt(normalNum);
console.log(result); // 110n

Cách 2: Chuyển BigInt thành Number (có thể mất độ chính xác)

let result = Number(bigNum) + normalNum;
console.log(result); // 110

hi chú:

  • Nếu cần chính xác 100%, hãy giữ BigInt.
  • Nếu số không quá lớn và cần dùng các phương thức Math, hãy chuyển về Number.

Lỗi khi dùng BigInt với các phương thức của Math

BigInt không hỗ trợ các phương thức trong đối tượng Math như Math.sqrt(), Math.pow(), Math.random(), v.v.

Ví dụ lỗi

let bigNumber = 144n;

console.log(Math.sqrt(bigNumber)); //  TypeError: Cannot convert a BigInt value to a number

Cách khắc phục

Cách 1: Chuyển BigInt thành Number trước khi dùng Math

let sqrtValue = Math.sqrt(Number(bigNumber));
console.log(sqrtValue); // 12

Cách 2: Sử dụng thuật toán thay thế nếu không thể chuyển đổi
Ví dụ: Nếu bạn cần tính căn bậc hai của BigInt mà không chuyển đổi về Number, bạn có thể dùng thuật toán Newton-Raphson hoặc tìm cách xấp xỉ.

Lưu ý về hiệu suất và bộ nhớ khi sử dụng BigInt

Vấn đề hiệu suất

BigInt không tối ưu cho các phép toán nhỏ, vì:

  • BigInt sử dụng nhiều bộ nhớ hơn Number.
  • Các phép toán trên BigInt chậm hơn so với Number, nhất là khi thực hiện phép nhân, chia, hoặc tìm số mũ lớn.

Ví dụ về tốc độ chậm hơn của BigInt

console.time("Number");
let sum1 = 0;
for (let i = 0; i < 1000000; i++) {
    sum1 += i; // Number
}
console.timeEnd("Number");

console.time("BigInt");
let sum2 = 0n;
for (let i = 0n; i < 1000000n; i++) {
    sum2 += i; // BigInt
}
console.timeEnd("BigInt");

Kết quả: BigInt chạy chậm hơn đáng kể so với Number.

Ứng dụng thực tế của BigInt trong JavaScript

BigInt mang lại lợi ích lớn khi làm việc với những con số vượt quá giới hạn của kiểu Number. Dưới đây là các ứng dụng thực tế của BigInt trong nhiều lĩnh vực khác nhau.

Xử lý số lớn trong mã hóa, bảo mật

Tại sao cần BigInt?

Trong lĩnh vực mã hóa và bảo mật, các thuật toán như RSA, Diffie-Hellman, ECC sử dụng số nguyên rất lớn để tạo và xử lý khóa bảo mật.

Number trong JavaScript chỉ hỗ trợ đến 2^53 - 1 (9,007,199,254,740,991), không đủ để lưu trữ và xử lý các khóa mã hóa có hàng trăm chữ số.

Ví dụ: Mô phỏng tạo số nguyên tố lớn trong mã hóa

function isPrime(n) {
    if (n < 2n) return false;
    for (let i = 2n; i * i <= n; i++) {
        if (n % i === 0n) return false;
    }
    return true;
}

let largePrime = 10000000000000061n; // Một số nguyên tố lớn
console.log(`Số ${largePrime} có phải số nguyên tố không?`, isPrime(largePrime));

Ứng dụng thực tế:

  • Sinh khóa RSA (1024-bit, 2048-bit).
  • Kiểm tra số nguyên tố trong mã hóa dữ liệu.

Tính toán tài chính với số liệu chính xác

Tại sao cần BigInt?

Trong tài chính, các phép tính tiền tệ yêu cầu độ chính xác cao. Sử dụng Number có thể gây lỗi do mất độ chính xác khi làm việc với số thập phân, ví dụ:

console.log(0.1 + 0.2); //  0.30000000000000004

Thay vì lưu trữ số tiền dưới dạng số thực (float), ta có thể lưu trữ dưới đơn vị nhỏ nhất (vd: xu, cents) dưới dạng BigInt để đảm bảo tính chính xác.

Ví dụ: Xử lý giao dịch tài chính với BigInt

let price = 1999999n;  // Giá sản phẩm (tính theo đơn vị xu, 1n = 1 xu)
let quantity = 3n;      // Số lượng sản phẩm
let total = price * quantity; // Tổng tiền

console.log(`Tổng tiền: ${total} xu (~ ${total / 100n} VND)`);
// Kết quả: Tổng tiền: 5999997 xu (~ 59999 VND)
  • Quản lý tài khoản ngân hàng, giao dịch tiền điện tử.
  • Xử lý tỷ giá hối đoái chính xác cao.
  • Kế toán, thuế, tính toán lãi suất.

Kết bài

BigInt là một bước tiến quan trọng trong JavaScript, giúp lập trình viên làm việc với số nguyên cực lớn mà không gặp giới hạn của kiểu Number. Với các ứng dụng thực tế trong mã hóa bảo mật, tài chính, và quản lý dữ liệu lớn, BigInt mang lại độ chính xác và tính linh hoạt cao hơn trong nhiều bài toán phức tạp.

Tuy nhiên, việc sử dụng BigInt cũng có một số hạn chế, như không thể kết hợp trực tiếp với Number và không hỗ trợ các hàm toán học trong Math. Vì vậy, khi áp dụng BigInt, cần cân nhắc về hiệu suất, bộ nhớ, và sự tương thích với các thư viện khác trong JavaScript.

Nhìn chung, nếu bạn cần xử lý số lớn với độ chính xác cao, đặc biệt trong mã hóa, tài chính và cơ sở dữ liệu, thì BigInt là lựa chọn tối ưu!

Bài viết liên quan

  • 2