0
0
Lập trình
Harry Tran
Harry Tran106580903228332612117

Tại sao kết quả của 0.1 + 0.2 lại không bằng 0.3 trong lập trình?

Đăng vào 1 tuần trước

• 2 phút đọc

Tại sao kết quả của 0.1 + 0.2 lại không bằng 0.3 trong lập trình?

Chắc hẳn lập trình viên JavaScript nào cũng đã từng nghe qua về vấn đề này. Tuy nhiên, đây không chỉ là vấn đề riêng của JavaScript. Tôi đã thử nghiệm với nhiều ngôn ngữ lập trình khác như Python, Java, C/C++ và kết quả đều cho thấy rằng:

Copy
0.1 + 0.2 == 0.3 // false

Nguyên nhân cốt lõi

Hầu hết các ngôn ngữ lập trình này tuân theo chuẩn IEEE-754 (https://www.geeksforgeeks.org/ieee-standard-754-floating-point-numbers/) để biểu diễn các số thực dấu phẩy động (floating-point number). Chuẩn IEEE-754 có những hạn chế trong việc biểu diễn chính xác các số này dưới dạng nhị phân (binary).

Ví dụ, khi biểu diễn 1/3 dưới dạng thập phân (decimal), chúng ta gặp khó khăn vì kết quả là 0.333333... không bao giờ dừng lại. Tương tự, các số 0.1 và 0.2 cũng rất khó để biểu diễn chính xác ở dạng nhị phân. Cụ thể, 0.1 (thập phân) được biểu diễn là 0.0001100110011... (nhị phân) và 0.2 (thập phân) là 0.001100110011... (nhị phân), với chuỗi 0011 lặp lại mãi.

Vì những lí do này, khi cộng các số có sai số biểu diễn với nhau, kết quả cuối cùng cũng sẽ mắc phải sai số!

Một điều thú vị: Mặc dù 0.1 + 0.2 == 0.3 trả về false, nhưng 0.1 + 0.1 == 0.2 lại trả về true. Bạn có biết tại sao lại như vậy không? (Đây là một câu hỏi mở dành cho các bạn.)

Dành cho những ai thích thông tin chính xác: Việc JavaScript áp dụng chuẩn IEEE-754 được ghi trong đặc tả ngôn ngữ, bạn có thể tìm hiểu thêm tại đây: https://tc39.es/ecma262/#sec-bibliography

Tại sao vẫn dùng chuẩn IEEE-754?

Xét một cách tổng thể, chuẩn IEEE-754 mang lại sự cân bằng giữa hiệu năng, độ chính xác và tính tương thích (bất kể bộ xử lý hay kiến trúc hệ thống là gì) cho hầu hết các ứng dụng thực tế. Tuy nhiên, chúng ta vẫn cần phải nhận thức về hạn chế của nó và tìm ra những giải pháp phù hợp.

Một vài giải pháp trong JavaScript

  1. Làm tròn (Rounding): Sử dụng hàm toFixed(). Ví dụ:

    Copy
    (0.1 + 0.2).toFixed(1); // "0.3"

    Đáng lưu ý rằng toFixed() trả về một chuỗi (string).

  2. Sử dụng thư viện: Các thư viện như decimal.js, big.js, dinero.js cung cấp giải pháp tính toán với độ chính xác cao hơn.

Bài chia sẻ đến đây là hết. Nếu bạn có những suy nghĩ hay giải pháp khác, hãy cùng để lại bình luận bên dưới nhé.

Tài liệu tham khảo:

Gợi ý câu hỏi phỏng vấn
Không có dữ liệu

Không có dữ liệu

Bài viết được đề xuất
Bài viết cùng tác giả

Bình luận

Chưa có bình luận nào

Chưa có bình luận nào