Hiểu các quy ước về dấu
Hai quy ước cho kết quả giống hệt nhau khi cả hai số đều dương, nhưng khác nhau mỗi khi có một giá trị âm, như bảng dưới đây.
| a | b | Kết quả sàn (dấu của b) | Kết quả cắt cụt (dấu của a) |
|---|---|---|---|
| 13 | 5 | 3 | 3 (giống nhau — cả hai đều dương) |
| −13 | 5 | 2 | −3 |
| 13 | −5 | −2 | 3 |
| −13 | −5 | −3 | −3 (giống nhau — cả hai đều âm) |
- Mod sàn (được dùng làm kết quả chính ở đây) là quy ước phổ biến nhất trong toán học thuần túy và lý thuyết số, và trùng với toán tử % có sẵn của Python.
- Mod cắt cụt (hiển thị làm kết quả phụ) trùng với toán tử % có sẵn trong JavaScript, C, C++, Java và hầu hết ngôn ngữ họ C, nơi dấu của phần dư theo số bị chia.
- Phép chia lấy dư cho 0 là không xác định và không được công cụ này tính; số chia phải là một số khác 0.
Phép chia lấy dư là gì?
Phép chia lấy dư, viết là a mod b (hoặc a % b), trả về phần dư khi chia a cho b. Ví dụ, 13 mod 5 = 3, vì 13 = 2 × 5 + 3 — chia 13 cho 5 được thương là 2 và dư 3. Phép chia lấy dư là nền tảng của lý thuyết số (số học modular hay số học đồng hồ), của khoa học máy tính (băm, đánh chỉ số vòng, tổng kiểm tra) và của cả suy luận thường ngày về phần dư và chu kỳ (như thứ trong tuần hay giờ trên mặt đồng hồ).
Có hai quy ước toán học được dùng rộng rãi để xác định dấu của kết quả khi có số âm tham gia: mod sàn, trong đó kết quả luôn mang cùng dấu với số chia b, và mod cắt cụt, trong đó kết quả luôn mang cùng dấu với số bị chia a. Cả hai đều là định nghĩa hợp lệ về 'phần dư' và cho kết quả trùng khớp hoàn toàn khi a và b đều dương; chúng chỉ khác nhau khi có giá trị âm.
Việc chọn quy ước nào có ý nghĩa thực tiễn vì các ngôn ngữ lập trình khác nhau cài đặt mặc định khác nhau: toán tử % của Python dùng mod sàn, trong khi JavaScript, C, C++, Java và hầu hết ngôn ngữ họ C dùng mod cắt cụt (trùng dấu với số bị chia). Công cụ này nêu rõ cả hai kết quả để bạn đọc trực tiếp theo quy ước mình cần.
Cách dùng máy tính phép chia lấy dư này
- Nhập số bị chia (a) — số được đem đi chia.
- Nhập số chia (b) — số mà bạn chia cho. Số chia không được bằng 0, vì phép chia (và phép chia lấy dư) cho 0 là không xác định.
- Đọc kết quả theo quy ước sàn (dấu luôn trùng số chia) — đây là quy ước toán học phổ biến nhất trong lý thuyết số.
- So sánh với kết quả theo quy ước cắt cụt (dấu luôn trùng số bị chia) nếu bạn cần khớp với toán tử % có sẵn của một ngôn ngữ lập trình cụ thể, và xem thương số cùng phương trình chia đầy đủ để hiểu từng bước.
Công thức mod sàn và mod cắt cụt
Mod sàn định nghĩa thương là q = ⌊a ÷ b⌋ (làm tròn xuống, về phía âm vô cực), rồi r = a − b×q. Cách này bảo đảm phần dư r luôn cùng dấu với số chia b (hoặc bằng 0), và thỏa mãn 0 ≤ r < |b| khi b > 0. Ví dụ minh họa: 13 mod 5: q = ⌊13/5⌋ = 2, r = 13 − 5×2 = 3.
Ví dụ minh họa với số bị chia âm: −13 mod 5 (quy ước sàn): q = ⌊−13/5⌋ = ⌊−2,6⌋ = −3, r = −13 − 5×(−3) = −13 + 15 = 2. Lưu ý kết quả là số dương (trùng dấu với số chia dương), khác với kết quả cắt cụt bên dưới.
Mod cắt cụt định nghĩa thương bằng cách làm tròn về phía 0 thay vì về phía âm vô cực, rồi tính phần dư theo cùng cách; điều này bảo đảm phần dư luôn cùng dấu với số bị chia a (hoặc bằng 0). Ví dụ minh họa: −13 mod 5 (cắt cụt, chính là kết quả của % trong JavaScript/C/Java): thương làm tròn −2,6 về phía 0 thành −2, nên r = −13 − 5×(−2) = −13 + 10 = −3 — số âm, trùng dấu với số bị chia âm, khác với kết quả sàn là +2 cho cùng đầu vào.
Những lỗi thường gặp
- Cho rằng mọi ngôn ngữ lập trình đều tính a mod b giống nhau với số âm — JavaScript, C, C++ và Java dùng mod cắt cụt, còn Python và nhiều giáo trình toán dùng mod sàn, và kết quả khác nhau mỗi khi a âm.
- Quên rằng kết quả sàn luôn mang dấu của số chia, chứ không phải của số bị chia — điều này ngược với quy ước cắt cụt (kiểu JavaScript).
- Cố tính a mod 0 — phép chia lấy dư, cũng như phép chia, là không xác định khi số chia bằng không.
- Dùng đầu vào không nguyên rồi mong đợi số học modular kiểu số nguyên — công cụ này chấp nhận số thực và áp dụng cùng logic sàn/cắt cụt, nhưng nhiều tính chất kinh điển của số học modular (như số học đồng hồ) chỉ được định nghĩa riêng cho số nguyên.
Câu hỏi thường gặp
Mod sàn và mod cắt cụt khác nhau như thế nào?
Mod sàn làm tròn thương về phía âm vô cực, nên phần dư luôn cùng dấu với số chia. Mod cắt cụt làm tròn thương về phía 0, nên phần dư luôn cùng dấu với số bị chia. Hai quy ước trùng nhau khi cả hai số đều dương nhưng khác nhau khi một trong hai số âm — ví dụ, −13 mod 5 bằng 2 theo quy ước sàn nhưng bằng −3 theo quy ước cắt cụt.
Tại sao −13 mod 5 cho kết quả khác nhau ở các máy tính khác nhau?
Điều đó phụ thuộc vào quy ước dấu được dùng. Mod sàn cho 2 (kết quả trùng dấu với số chia dương và thỏa mãn 0 ≤ r < 5). Mod cắt cụt cho −3 (kết quả trùng dấu với số bị chia âm). Toán tử % của Python trả về 2 (sàn); toán tử % của JavaScript, C và Java trả về −3 (cắt cụt). Không quy ước nào 'đúng hơn' — đó là hai định nghĩa toán học khác nhau và đều hợp lệ như nhau.
Tính a mod b bằng tay như thế nào?
Chia a cho b để được thương, làm tròn thương theo quy ước bạn chọn (làm tròn xuống với quy ước sàn, làm tròn về phía 0 với quy ước cắt cụt), rồi lấy a trừ đi b nhân với thương đã làm tròn: phần dư = a − b × thương. Với 13 mod 5: 13 ÷ 5 = 2,6, làm tròn thành thương 2 theo cả hai quy ước, nên phần dư = 13 − 5×2 = 3.
Mod nghĩa là gì trong số học modular và số học đồng hồ?
Số học modular coi các số như 'quay vòng lại' sau khi đạt tới modulus — ví dụ kinh điển là đồng hồ 12 giờ, nơi thời gian được tính mod 12 (hoặc mod 24 với hệ 24 giờ). Chẳng hạn, 15 giờ theo cách ghi 24 giờ tương ứng với 15 mod 12 = 3 trên mặt đồng hồ 12 giờ. Phép chia lấy dư chính là phép toán tạo ra phần dư 'quay vòng' đó.
Có thể lấy mod với số chia âm không?
Có. Theo quy ước sàn, a mod b (với b âm) cho phần dư cùng dấu với b — ví dụ, 13 mod −5 = −2, vì 13 = (−3)×(−5) + (−2). Theo quy ước cắt cụt, phần dư lại trùng dấu với số bị chia: 13 mod −5 = 3 khi cắt cụt, vì thương làm tròn về phía 0 thành −2, cho 13 − (−5)×(−2) = 13 − 10 = 3.
Tài liệu tham khảo
- Rosen KH. Elementary Number Theory and Its Applications. 6th ed. Pearson, 2010. (Division algorithm and modular arithmetic.)
- Leijen D. Division and Modulus for Computer Scientists. Utrecht University Technical Report UU-CS-2001-20, 2001. (Formal comparison of flooring, truncating and Euclidean division conventions.)
- ECMA International. ECMA-262: ECMAScript Language Specification — the remainder operator (%). ecma-international.org.