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

JavaScript Math.round với số âm: vì sao -1.5 thành -1?

Math.round(-1.5) trả -1, không phải -2. Nếu nghĩ làm tròn luôn đẩy phần .5 ra xa số 0, kết quả phía âm sẽ khác kỳ vọng. Khi dùng số nguyên cho tọa độ hoặc hiển thị, cần ghi rõ cách xử lý giá trị nằm chính giữa hai số nguyên.

JavaScript Math.round với số âm: vì sao -1.5 thành -1?

Math.round(-1.5) trả -1, không phải -2. Nếu nghĩ làm tròn luôn đẩy phần .5 ra xa số 0, kết quả phía âm sẽ khác kỳ vọng. Khi dùng số nguyên cho tọa độ hoặc hiển thị, cần ghi rõ cách xử lý giá trị nằm chính giữa hai số nguyên.

1. Điểm giữa được chọn về phía dương

console.log(Math.round(1.5)); // 2
console.log(Math.round(-1.5)); // -1
console.log(Math.round(-1.51)); // -2
console.log(Math.round(-1.49)); // -1
console.log(Object.is(Math.round(-0.5), -0)); // true

MDN Math.round mô tả việc chọn số nguyên gần nhất, và khi cách đều thì chọn phía +Infinity. Với -1.5, hai ứng viên là -2 và -1; phía dương hơn là -1. Quy tắc này khác cách làm tròn điểm giữa ra xa số 0.

Trường hợp -0.5 còn cho -0. Nếu chỉ nhìn chuỗi hiển thị 0, có thể không nhận ra dấu của kết quả. Quyết định có cần giữ dấu số 0 phải nằm trong contract của ứng dụng, thay vì được suy ra từ ảnh chụp giao diện.

2. floor và ceil không có nghĩa giảm hay tăng độ lớn

console.log(Math.floor(1.2)); // 1
console.log(Math.ceil(1.2)); // 2
console.log(Math.floor(-1.2)); // -2
console.log(Math.ceil(-1.2)); // -1

Math.floor chọn số nguyên lớn nhất không vượt đầu vào; Math.ceil chọn số nguyên nhỏ nhất không thấp hơn đầu vào. Trên trục số, floor đi về phía âm, ceil đi về phía dương.

Vì vậy, “làm tròn xuống” số âm có thể làm độ lớn tăng. Chọn hàm theo điều kiện cần bảo đảm: không vượt ranh giới, không thấp hơn ranh giới hay gần giá trị gốc nhất. Ba yêu cầu đó không tương đương.

3. Đặt contract rõ ràng cho tọa độ nguyên

function roundCoordinate(value) {
  if (!Number.isFinite(value)) {
    throw new TypeError('coordinate must be a finite number');
  }
  if (Math.abs(value) > 1_000_000) {
    throw new RangeError('coordinate is outside the supported range');
  }
  const rounded = Math.round(value);
  return rounded === 0 ? 0 : rounded;
}
console.log(roundCoordinate(1.5)); // 2
console.log(roundCoordinate(-1.5)); // -1
console.log(Object.is(roundCoordinate(-0.5), -0)); // false

Helper minh họa nhận number hữu hạn trong khoảng từ -1.000.000 đến 1.000.000. Nó làm tròn tới số nguyên gần nhất theo quy tắc Math.round và chuẩn hóa mọi kết quả bằng 0 thành +0. Giới hạn miền là lựa chọn ứng dụng; helper không chuyển chuỗi số hoặc tự chặn giá trị vượt miền về biên.

Đây chỉ là chính sách số học cho tọa độ, chưa phải giải pháp căn chỉnh hình ảnh theo device pixel ratio hoặc transform của trình duyệt. Nếu thuật toán cần giữ tọa độ phần lẻ để tránh tích lũy sai lệch khi kéo thả, giữ dữ liệu gốc và chỉ làm tròn ở bước xuất phù hợp.

4. Làm tròn sớm có thể thay đổi tổng

Làm tròn từng bước và làm tròn sau khi cộng có thể cho kết quả khác nhau. Chẳng hạn hai độ dời 0,4 cộng lại là 0,8; làm tròn từng độ dời trước có thể làm mất toàn bộ chuyển động nhỏ. Chọn thời điểm làm tròn cùng với quy tắc điểm giữa.

Bài này chỉ xét làm tròn tới số nguyên trên giá trị Number đã có. Không suy rộng helper thành một bộ làm tròn thập phân chính xác cho mọi định dạng dữ liệu. Nếu yêu cầu liên quan đến độ chính xác khác, cần chọn biểu diễn và thuật toán tương ứng rồi kiểm tra riêng.

5. Checklist trước khi chọn hàm làm tròn

  • Cần số gần nhất, không vượt hay không thấp hơn đầu vào?
  • Đã thử cả điểm giữa dương và âm?
  • Kết quả -0 cần được giữ hay chuẩn hóa?
  • Đầu vào sai kiểu và không hữu hạn được xử lý ở đâu?
  • Làm tròn ở từng bước hay ở đầu ra cuối cùng?

Sáu khối mã Việt–Anh đã chạy bằng Node.js, kèm kiểm tra ranh giới, đầu vào sai và khác biệt giữa làm tròn từng bước với làm tròn tổng. Chưa kiểm thử giao diện kéo thả hoặc căn chỉnh pixel thực 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.