Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> JavaScript

Phép toán dấu phẩy động (Floating-point) trong JavaScript có chính xác 100% không?

Không. JS dùng chuẩn IEEE 754 double-precision (64-bit) cho mọi số. Nhiều số thập phân không biểu diễn chính xác được trong nhị phân → rounding errors.

Ví dụ kinh điển

<script>
  document.write(0.1 + 0.2); // 0.30000000000000004
  document.write('<br>');
  document.write(0.3 + 0.6); // 0.8999999999999999
  document.write('<br>');
  document.write(0.2 + 0.1); // 0.30000000000000004
</script>

Tại sao?

Số thập phân như 0.1, 0.2, 0.3 là số vô hạn tuần hoàn trong nhị phân (giống 1/3 = 0.333... trong thập phân). Máy tính cắt bớt → sai số nhỏ.

Giải pháp phổ biến

1. Nhân chia hệ số 10^n (Integer math)

function addFloat(a, b, precision = 2) {
  const factor = 10 ** precision;
  return Math.round(a * factor + b * factor) / factor;
}
addFloat(0.1, 0.2); // 0.3

2. toFixed() + Number() — Cho hiển thị

Number((0.1 + 0.2).toFixed(2)); // 0.3
// Lưu ý: toFixed trả về STRING

3. Thư viện: decimal.js, big.js, bignumber.js

import Decimal from 'decimal.js';
new Decimal(0.1).plus(0.2).toNumber(); // 0.3 — chính xác tuyệt đối

4. Epsilon comparison (so sánh gần đúng)

function floatEquals(a, b, epsilon = Number.EPSILON) {
  return Math.abs(a - b) < epsilon;
}
floatEquals(0.1 + 0.2, 0.3); // true

Khi nào cần quan tâm?

  • Tính toán tài chính, tiền tệ — bắt buộc dùng integer (cents) hoặc decimal library.
  • So sánh equality — dùng epsilon.
  • Hiển thị UI — dùng toFixed, Intl.NumberFormat.
  • Toán học khoa học — chấp nhận error nhỏ, dùng library nếu cần chính xác.

Number.EPSILON

Sai số nhỏ nhất giữa 1 và số tiếp theo > 1: ~2.22e-16. Dùng làm epsilon mặc định cho so sánh float.

Tóm tắt

Vấn đềGiải pháp
0.1 + 0.2 !== 0.3Integer math (cents), decimal.js, toFixed()
So sánh floatMath.abs(a-b) < Number.EPSILON
Hiển thị tiền tệIntl.NumberFormat('vi-VN', {style:'currency', currency:'VND'})
Tính toán khoa học lớnbig.js, decimal.js