Back to Explore
Sai lầm 0.1 + 0.2 và bài học xương máu về xử lý số thực trong ứng dụng Fintech với NestJS

Sai lầm 0.1 + 0.2 và bài học xương máu về xử lý số thực trong ứng dụng Fintech với NestJS

Khám phá nguyên nhân tại sao phép toán 0.1 cộng 0.2 lại gây ra thảm họa tài chính trong các ứng dụng Fintech và cách thức NestJS cùng các giải pháp kỹ thuật giúp bạn ngăn chặn triệt để lỗi làm tròn số này.

Website
Upvote this postSign in to upvote this article.

Bài viết được dịch và tổng hợp từ tin tức gốc. Bạn có thể đọc bài viết gốc bằng tiếng Anh tại đây.

Điểm tin nhanh:

  • Lỗi số thực dấu phẩy động (Floating-point) trong JavaScript là nguyên nhân hàng đầu gây sai lệch dữ liệu tài chính.
  • Phép toán 0.1 + 0.2 không bằng 0.3 chính xác trong hệ nhị phân, dẫn đến sai số tích lũy nguy hiểm.
  • Sử dụng thư viện chuyên dụng như Decimal.js hoặc Big.js kết hợp với kiến trúc NestJS là giải pháp tiêu chuẩn để bảo vệ tính toàn vẹn của dữ liệu.

Trong thế giới lập trình, có những lỗi nhỏ đến mức chúng ta thường bỏ qua, nhưng đối với các hệ thống Fintech, đó có thể là khởi đầu của một thảm họa tài chính. Bạn đã bao giờ tự hỏi tại sao 0.1 cộng 0.2 trong JavaScript lại cho ra kết quả 0.30000000000000004 chưa? Nếu bạn đang xây dựng một hệ thống xử lý giao dịch, con số sai lệch dù chỉ là 0.00000000000000004 cũng đủ để phá vỡ sự tin tưởng của khách hàng và gây ra những rắc rối pháp lý không đáng có. Việc hiểu rõ bản chất của dữ liệu là bước đầu tiên trong tư duy thiết kế hệ thống xử lý lỗi chuẩn chuyên gia.

Bản chất của vấn đề: Tại sao máy tính lại tính sai?

JavaScript sử dụng chuẩn IEEE 754 để biểu diễn số thực, tức là các số được lưu trữ dưới dạng nhị phân. Vấn đề nằm ở chỗ, nhiều số thập phân không thể biểu diễn chính xác dưới dạng nhị phân hữu hạn, dẫn đến việc làm tròn số. Khi bạn thực hiện hàng triệu phép tính trong một ứng dụng tài chính, sai số này sẽ tích lũy dần lên.

Ảnh bìa bài viết

Bảng so sánh sai số trong tính toán

Phép toán Kết quả mong đợi Kết quả thực tế (JS) Sai số
0.1 + 0.2 0.3 0.30000000000000004 4e-17
1.005 * 100 100.5 100.49999999999999 1e-14

Giải pháp: Xử lý số học trong NestJS

Để ngăn chặn cơn ác mộng này, chúng ta không thể dựa vào các kiểu dữ liệu nguyên thủy (primitive types) của JavaScript. Thay vào đó, hãy sử dụng các thư viện chuyên dụng như Decimal.js hoặc Big.js.

Cấu trúc xử lý dữ liệu an toàn

Khi làm việc với NestJS, bạn nên đóng gói logic tính toán vào các Service hoặc Utility Class. Dưới đây là cách triển khai cơ bản:

import { Decimal } from 'decimal.js';

export class FinanceService {
  calculateTotal(amount: string, tax: string): string {
    const a = new Decimal(amount);
    const b = new Decimal(tax);
    return a.plus(b).toString();
  }
}

Việc tách biệt logic này giúp bạn dễ dàng kiểm soát, tương tự như cách chúng ta tối ưu hóa quy trình xử lý PDF bằng cách xây dựng các API tập trung thay vì lặp lại code ở nhiều nơi.

Cover image for I once watched a fintech app lose money to 0.1 plus 0.2, here is how NestJS stops that nightmare

Đánh giá & Lời khuyên Thực tiễn

Từ góc độ của một Senior Tech Lead, tôi đánh giá việc sử dụng thư viện số học chính xác là bắt buộc đối với mọi dự án Fintech.

  • Ưu điểm: Loại bỏ hoàn toàn sai số làm tròn, đảm bảo tính nhất quán giữa frontend và backend.
  • Nhược điểm: Hiệu năng tính toán chậm hơn so với số nguyên thủy do phải xử lý qua object wrapper.
  • Lưu ý quan trọng: Luôn lưu trữ số tiền dưới dạng Integer (đơn vị nhỏ nhất như cents) trong Database thay vì Float để tránh rủi ro khi truy vấn hoặc thực hiện các phép tính trực tiếp trên SQL.

Nếu bạn đang đối mặt với các vấn đề về hiệu năng hệ thống, hãy tham khảo thêm về chiến lược xử lý hàng triệu bản ghi trên Shopify để có cái nhìn tổng quan về cách tối ưu hóa dữ liệu quy mô lớn.

Câu hỏi thường gặp (FAQ)

Tại sao không nên dùng Float trong cơ sở dữ liệu?

Vì kiểu dữ liệu Float không đảm bảo độ chính xác tuyệt đối cho các phép tính tài chính, dẫn đến việc dữ liệu bị sai lệch sau nhiều lần cập nhật.

Thư viện nào tốt nhất cho NestJS?

Decimal.js là lựa chọn phổ biến nhất nhờ khả năng hỗ trợ đầy đủ các phép toán phức tạp và độ chính xác cao.

Có cần chuyển đổi kiểu dữ liệu ở tầng API không?

Có, bạn nên nhận dữ liệu dưới dạng string từ client và chuyển đổi sang Decimal ngay tại tầng Service để đảm bảo tính an toàn xuyên suốt hệ thống.

Kết luận

Sai lầm từ những phép toán cơ bản có thể gây ra hậu quả nghiêm trọng trong các hệ thống đòi hỏi độ chính xác cao. Bằng cách áp dụng các thư viện xử lý số học chuyên dụng và tuân thủ nguyên tắc lưu trữ dữ liệu đúng cách, bạn sẽ bảo vệ được hệ thống của mình khỏi những rủi ro không đáng có. Hãy bắt đầu refactor lại các module tính toán trong dự án của bạn ngay hôm nay. Nếu bạn thấy bài viết này hữu ích, đừng quên theo dõi hi_dev để cập nhật thêm nhiều kiến thức chuyên sâu về kiến trúc phần mềm và công nghệ mới nhất.

Discussion (0)

You need to log in to post comments. Log In

No comments yet. Start the discussion!