Lập trình · 21/10/2026

JavaScript: ép số nguyên bằng | 0 có thể làm đổi dấu

Một số dương lớn bỗng thành số âm sau thao tác “bỏ phần thập phân”. Cách viết value | 0 có thể trông giống một phép rút gọn tiện lợi, nhưng với Number, nó đưa dữ liệu qua biểu diễn số nguyên có dấu 32 bit. Điều này khác mục tiêu chỉ bỏ phần lẻ.

JavaScript: ép số nguyên bằng | 0 có thể làm đổi dấu

Một số dương lớn bỗng thành số âm sau thao tác “bỏ phần thập phân”. Cách viết value | 0 có thể trông giống một phép rút gọn tiện lợi, nhưng với Number, nó đưa dữ liệu qua biểu diễn số nguyên có dấu 32 bit. Điều này khác mục tiêu chỉ bỏ phần lẻ.

1. Số vượt miền 32 bit có thể đổi giá trị

const value = 3_000_000_000;
console.log(value | 0); // -1294967296
console.log(Math.trunc(value)); // 3000000000
console.log(4_294_967_296 | 0); // 0

Các kết quả này không phải sai số làm tròn thông thường. Phép OR theo bit với Number dùng số nguyên có dấu 32 bit, nên không giữ nguyên mọi số nguyên lớn. Xem MDN Bitwise OR.

Với số byte đã truyền, bộ đếm tích lũy hoặc giá trị đo lớn, test chỉ dùng 1, 2 và 3 sẽ không phát hiện lỗi. Cần đưa cả giá trị vượt 2^31 và 2^32 vào bộ kiểm thử nếu miền dữ liệu có thể chạm tới chúng.

2. Bỏ phần lẻ khác với làm tròn xuống

console.log(-3.9 | 0); // -3
console.log(Math.trunc(-3.9)); // -3
console.log(Math.floor(-3.9)); // -4

Math.trunc bỏ phần phân số theo hướng về 0; floor đi về phía âm vô cùng. Tham khảo MDN Math.trunc. Hai phép không thể hoán đổi chỉ vì cho cùng kết quả với một số đầu vào dương.

Trước khi chọn hàm, viết rõ ví dụ nghiệp vụ với số âm. Một giá trị thời gian chênh lệch, độ lệch tọa độ hoặc chỉ số đã tính toán có thể yêu cầu quy tắc khác nhau; tên biến “integer” không xác định được cách làm tròn.

3. Phép toán bit có thể biến dữ liệu lỗi thành 0

console.log(NaN | 0); // 0
console.log(Infinity | 0); // 0
console.log('bad' | 0); // 0
console.log(Number.isNaN(Math.trunc(NaN))); // true

Trong ví dụ, ba loại đầu vào khác nhau bị gom về cùng số 0 khi dùng | 0. Nếu 0 có nghĩa là phép đo thật bằng không, bước chuyển đổi này che mất thông tin đầu vào lỗi.

Math.trunc cũng không tự cung cấp toàn bộ contract dữ liệu: nó có thể chuyển một số đầu vào khác kiểu thành Number. Khi hệ thống chỉ chấp nhận Number hữu hạn, hãy kiểm tra trước thay vì dùng phép tính như một bộ xác thực.

4. Tách xác thực khỏi thao tác bỏ phần lẻ

function truncateMeasurement(value) {
  if (!Number.isFinite(value)) {
    throw new TypeError('measurement must be a finite number');
  }
  if (Math.abs(value) > 1_000_000_000_000) {
    throw new RangeError('measurement is outside the supported range');
  }
  return Math.trunc(value);
}
console.log(truncateMeasurement(3_000_000_000.75)); // 3000000000
console.log(truncateMeasurement(-3.9)); // -3

Helper minh họa nhận Number hữu hạn và giới hạn trị tuyệt đối không quá một nghìn tỷ. Đây là giới hạn ứng dụng giả định, không phải giới hạn JavaScript. Number.isFinite không tự chuyển chuỗi thành số; xem MDN Number.isFinite.

Nếu nguồn là chuỗi từ form, định nghĩa bước phân tích chuỗi riêng và báo lỗi đúng chỗ. Nếu giá trị đã mất độ chính xác trước khi đến helper, Math.trunc không thể khôi phục phần thông tin đã mất. Kiểu dữ liệu và quy tắc trao đổi phải phù hợp ngay từ đầu.

5. Review các phép chuyển đổi viết tắt

  • Tìm | 0, ~~ và các phép dịch bit dùng với ý định bỏ phần lẻ.
  • Thử số lớn, số âm, NaN, Infinity và chuỗi không phải số.
  • Ghi rõ cần truncation, floor hay một quy tắc làm tròn khác.
  • Kiểm tra kiểu và miền giá trị trước khi tính.
  • Giữ phép toán bit cho trường hợp thực sự cần thao tác bit theo contract.

Bài tập trung vào Number, không áp các nhận xét chuyển đổi 32 bit này cho phép OR giữa hai BigInt. Tám khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra biên miền dữ liệu và đầu vào sai kiểu. Không thực hiện benchmark hay tích hợp thiết bị đo thật.

Thảo luận

Bình luận 0

Đăng nhập để bình luận

Bạn cần có tài khoản để tham gia thảo luận và trả lời độc giả khác.

Đăng nhậpĐăng ký

Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.