Chuyển đến nội dung chính

Toán tử Modulo trong Python: Hiểu các khái niệm cốt lõi

Tìm hiểu cách dùng toán tử modulo (%) trong Python để giải quyết bài toán thực tế, từ kiểm tra chẵn/lẻ đến mật mã học hoặc cấu trúc dữ liệu chu kỳ.
· 9 phút đọc

Khám phá cùng AI

Toán tử modulo (%) trong Python là một toán tử số học cơ bản dùng để xác định phần dư của phép chia. Dù khái niệm đơn giản, nó đóng vai trò quan trọng trong nhiều ứng dụng lập trình. Từ việc kiểm tra một số là chẵn hay lẻ đến xoay vòng qua các dãy và xác định năm nhuận, nắm vững toán tử modulo sẽ nâng cao kỹ năng giải quyết vấn đề của bạn trong Python.

Hiểu toán tử modulo là điều thiết yếu vì nó thường xuất hiện trong:

  • Nhận diện số chẵn và số lẻ
  • Duyệt phần tử theo chu kỳ
  • Triển khai các phép tính trong số học mô-đun
  • Ứng dụng thực tế như tính toán ngày tháng, mật mã học và logic trò chơi.

Trong bài viết này, tôi sẽ cung cấp hướng dẫn toàn diện về cách sử dụng toán tử modulo trong Python, bao gồm cú pháp, hành vi với các kiểu số khác nhau, trường hợp sử dụng và ví dụ thực tiễn. Nếu bạn mới học Python, hãy cân nhắc tham gia khóa học Giới thiệu về Python của chúng tôi. 

Toán tử Modulo trong Python là gì?

Toán tử modulo (%) tính phần dư của phép chia giữa hai số. Với hai số a (số bị chia) và b (số chia), phép modulo trả về phần dư khi a được chia cho b.

Cơ sở toán học

Modulo bắt nguồn từ số học mô-đun, một hệ thống số học cho số nguyên trong đó các số sẽ “quay vòng” sau khi đạt đến một giá trị nhất định (mô-đun). Nó được sử dụng rộng rãi trong mật mã, băm và các phép tính mang tính chu kỳ.

Hãy nghĩ về đồng hồ 12 giờ: sau 12, thay vì tiếp tục đến 13, ta quay lại 1. Về bản chất đây là số học mô-đun với mô-đun bằng 12:

  • 13 % 12 = 1, nghĩa là 13 giờ tương ứng với 1 giờ trong định dạng 12 giờ.

Cú pháp và cách dùng cơ bản của Modulo trong Python

Trong Python, toán tử modulo có cú pháp đơn giản:

remainder = dividend % divisor

Hãy xem một vài ví dụ cơ bản:

# Basic modulo operations
print(7 % 3)     
print(15 % 4)   
print(20 % 5)  
1 
3 
0 

Khi chia 7 cho 3, ta được 2 dư 1. Toán tử modulo trả về phần dư đó. Tương tự, 15 chia cho 4 được 3 dư 3, và 20 chia cho 5 được đúng 4 không dư.

Làm việc với số nguyên

Giờ khi đã hiểu những điều cơ bản về toán tử modulo, hãy khám phá cách nó hoạt động với số nguyên.

Modulo với số nguyên dương

Làm việc với số nguyên dương là trường hợp đơn giản nhất cho toán tử modulo:

# Examples with positive integers
print(10 % 3)      
print(25 % 7)     
print(100 % 10)  
1 
4 
0 

Trong các ví dụ này, ta có thể tính kết quả bằng cách xác định số lần số chia “lọt” vào số bị chia rồi tìm phần còn lại:

  • 10 ÷ 3 = 3 dư 1, nên 10 % 3 = 1
  • 25 ÷ 7 = 3 dư 4, nên 25 % 7 = 4
  • 100 ÷ 10 = 10 dư 0, nên 100 % 10 = 0

Modulo với số nguyên âm

Hành vi của toán tử modulo trở nên thú vị hơn khi làm việc với số âm. Python tuân theo một quy tắc cụ thể: kết quả của a % b luôn cùng dấu với b (số chia).

# Examples with negative integers
print(-10 % 3)    
print(10 % -3)    
print(-10 % -3) 
2 
-2 
-1 

Những kết quả này có thể ban đầu khó hiểu, nhưng chúng tuân theo một quy tắc nhất quán:

  1. Với -10 % 3: Thay vì nhận -1 (nếu nghĩ -10 ÷ 3 = -3 dư -1), Python trả về 2. Đó là vì Python tìm một giá trị trong khoảng từ 0 đến 3 (không gồm 3) sao cho khi cộng với một bội số của 3 sẽ được -10. Đáp án là 2, vì -12 + 2 = -10.
  2. Với 10 % -3: Kết quả có cùng dấu với số chia (-3), nên ta được -2. Vì 10 = (-3) × (-4) + (-2).
  3. Với -10 % -3: Kết quả là -1, vì -10 = (-3) × 3 + (-1).

Hiểu cách Python xử lý số âm trong phép modulo rất quan trọng khi làm việc với các phép tính chu kỳ, chẳng hạn như:

  • Triển khai hàm băm
  • Giải bài toán liên quan đến số học đồng hồ
  • Xử lý logic chỉ số âm trong danh sách

Sử dụng Modulo với số dấu phẩy động

Toán tử modulo của Python không chỉ giới hạn ở số nguyên; nó cũng hoạt động với số dấu phẩy động:

# Modulo with floating-point numbers
print(7.5 % 2)     
print(9.7 % 4.2)  
print(5.0 % 0.2)  
1.5
1.299999999999999
0.19999999999999973

Với số dấu phẩy động, phép modulo tuân theo cùng nguyên tắc: trả về phần dư sau phép chia. Tuy nhiên, do cách số dấu phẩy động được lưu trữ trong máy tính (định dạng IEEE 754), có thể xuất hiện các sai số làm tròn nhỏ.

Ví dụ, thay vì 1.3, Python trả về 1.299999999999999, và thay vì 0.2, nó trả về 0.19999999999999973. Những sai số nhỏ này là phổ biến trong số học dấu phẩy động và cần được cân nhắc khi thực hiện các phép tính đòi hỏi độ chính xác cao.

Python cũng cung cấp hàm math.fmod() từ mô-đun math như một lựa chọn thay thế cho phép modulo với số dấu phẩy động, có thể xử lý khác nhau ở một số trường hợp biên:

import math

print(math.fmod(7.5, 2))    
print(math.fmod(-7.5, 2))  

# Compare with Python's modulo operator 
print(-7.5 % 2) 
1.5
-1.5
0.5

Khác biệt chính giữa % và math.fmod() là cách chúng xử lý số âm. Trong khi % đảm bảo kết quả cùng dấu với số chia và trả về giá trị trong khoảng [0, số chia), math.fmod() đảm bảo kết quả cùng dấu với số bị chia. Sự khác biệt này quan trọng trong những ứng dụng mà dấu của phần dư có ý nghĩa.

Vậy khi nào nên dùng % và khi nào dùng math.fmod()?

  • Dùng % khi bạn cần hành vi dấu nhất quán (ví dụ: xoay vòng trong một khoảng).
  • Dùng math.fmod() khi cần giữ nguyên dấu của số bị chia, như trong mô phỏng vật lý hoặc các hàm toán học.

Xử lý số âm trong modulo của Python

Như đã thấy ở các ví dụ trước, cách cài đặt toán tử modulo của Python với số âm có thể không trùng khớp trực giác ban đầu. Hãy khám phá hành vi này một cách có hệ thống hơn:

# Understanding the pattern with negative numbers
for i in range(-10, 11):
    result = i % 3
    print(f"{i} % 3 = {result}")
-10 % 3 = 2
-9 % 3 = 0
-8 % 3 = 1
-7 % 3 = 2
-6 % 3 = 0
-5 % 3 = 1
-4 % 3 = 2
-3 % 3 = 0
-2 % 3 = 1
-1 % 3 = 2
0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
7 % 3 = 1
8 % 3 = 2
9 % 3 = 0
10 % 3 = 1

Hãy chú ý mô hình: kết quả lặp lại 0 → 1 → 2 liên tục, bất kể số bị chia là dương hay âm. Tính nhất quán này khiến toán tử modulo đặc biệt hữu ích trong các phép tính chu kỳ, chẳng hạn như:

  • Xoay vòng qua chỉ số trong mảng hay bộ đệm vòng
  • Ánh xạ giá trị trong các hàm tuần hoàn (ví dụ: tính toán theo thời gian)

Công thức toán học mà Python tuân theo cho modulo là:

Import math 

a % b = a - (b * math.floor(a / b))

Điều này đảm bảo kết quả luôn nằm giữa 0 và b (không gồm b) khi b dương, hoặc giữa b và 0 (không gồm 0) khi b âm.

Tóm tắt về toán tử Modulo của Python

Toán tử modulo (%) trong Python tính phần dư của một phép chia. Nó tuân theo một công thức toán học nhất quán:

a % b = a - (b * math.floor(a / b))

Các quy tắc chính về hành vi của Modulo trong Python:

  1. Với số chia dương (b > 0)
    • Kết quả luôn nằm trong khoảng [0, b) (bao gồm 0, không gồm b).
  2. Với số chia âm (b < 0)
    • Kết quả luôn nằm trong khoảng (b, 0] (không gồm b, bao gồm 0).
    • Phần dư nhận cùng dấu với b (số chia).
  3. Hoạt động với cả số nguyên và số dấu phẩy động
    • Với số dấu phẩy động, % tuân theo cùng công thức nhưng có thể phát sinh sai số làm tròn nhỏ do độ chính xác dấu phẩy động.
  4. Khác biệt giữa % và math.fmod()
    • % đảm bảo phần dư cùng dấu với số chia.
    • math.fmod(a, b) đảm bảo phần dư cùng dấu với số bị chia.

Các trường hợp sử dụng phổ biến của toán tử Modulo

Hãy cùng xem một số ứng dụng thực tiễn của toán tử modulo và các ví dụ bổ sung. 

Kiểm tra số chẵn hay lẻ

Một trong những ứng dụng phổ biến nhất của toán tử modulo là xác định một số là chẵn hay lẻ:

def is_even(number):
    return number % 2 == 0

def is_odd(number):
    return number % 2 != 0

# Testing the functions
numbers = [1, 2, -3, 4, -5, 6, 7]
for num in numbers:
    if is_even(num):
        print(f"{num} is even")
    else:
        print(f"{num} is odd")
1 is odd
2 is even
-3 is odd
4 is even
-5 is odd
6 is even
7 is odd

Điều này hoạt động vì số chẵn cho phần dư 0 khi chia cho 2, còn số lẻ cho phần dư 1 hoặc -1.

Xoay vòng qua một dãy

Toán tử modulo rất phù hợp để tạo hành vi chu kỳ, như xoay vòng qua một danh sách phần tử:

days = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

def get_day(n):
    # Get the day of the week for the nth day, where day 0 is Monday
    return days[n % len(days)]

# Starting from Monday (day 0), what day is it after 10 days?
print(get_day(10))  # Output: "Thursday"

# What day was it 15 days ago from Monday?
print(get_day(-15))  # Output: "Sunday"
Thursday
Sunday

Trong ví dụ này, dù n lớn hay nhỏ (âm) bao nhiêu, hàm vẫn luôn trả về một ngày hợp lệ trong tuần.

Tính năm nhuận

Dù việc tính năm nhuận gồm nhiều điều kiện, toán tử modulo là trung tâm của thuật toán:

Năm nhuận tuân theo quy tắc cụ thể:

  • Một năm là năm nhuận nếu chia hết cho 4.
  • Nhưng nếu chia hết cho 100 thì không phải năm nhuận.
  • Trừ khi cũng chia hết cho 400, khi đó lại là năm nhuận.
def is_leap_year(year):

    return (year % 4 == 0 and year % 100 != 0) or (year % 400 == 0)

# Test the function
years = [1900, 2000, 2004, 2020, 2023, 2024]
for year in years:
    if is_leap_year(year):
        print(f"{year} is a leap year")
    else:
        print(f"{year} is not a leap year")
1900 is not a leap year
2000 is a leap year
2004 is a leap year
2020 is a leap year
2023 is not a leap year
2024 is a leap year

Điều này đảm bảo áp dụng đúng các quy tắc năm nhuận trong lịch Gregory.

Ví dụ thực tiễn về modulo trong Python

Dưới đây là một số cách bạn có thể dùng toán tử modulo trong các dự án Python của riêng bạn: 

Dùng modulo trong vòng lặp

Toán tử modulo thường được dùng trong vòng lặp để thực hiện thao tác theo chu kỳ đều đặn:

# Print a message every 5 iterations
for i in range(1, 11):
    print(f"Processing item {i}", end=": ")
    if i % 5 == 0:
        print("Checkpoint reached!")
    else:
        print("Continuing...")
Processing item 1: Continuing...
Processing item 2: Continuing...
Processing item 3: Continuing...
Processing item 4: Continuing...
Processing item 5: Checkpoint reached!
Processing item 6: Continuing...
Processing item 7: Continuing...
Processing item 8: Continuing...
Processing item 9: Continuing...
Processing item 10: Checkpoint reached!

Mẫu này hữu ích cho xử lý theo lô, báo cáo tiến độ hoặc triển khai bất kỳ chức năng nào cần diễn ra theo chu kỳ.

Modulo trong ứng dụng thực tế

Băm mật khẩu

Trong các ứng dụng mật mã, số học mô-đun là nền tảng. Dưới đây là ví dụ đơn giản hóa về cách modulo có thể được dùng trong một hàm băm cơ bản:

def simple_hash(text, modulus=1000000007):
    """A very simple hash function using modulo."""
    hash_value = 0
    for char in text:
        # Combine the current hash with the character's Unicode code point
        hash_value = (hash_value * 31 + ord(char)) % modulus
    return hash_value

# Test with some strings
print(simple_hash("hello"))  # Output a number between 0 and 1000000006
print(simple_hash("world"))
print(simple_hash("hello world"))
print(simple_hash("こんにちは"))  
99162322
113318802
204910434
807637228

Đây là ví dụ rất cơ bản, vì băm mật mã thực tế phức tạp hơn nhiều. Phép modulo đảm bảo giá trị băm nằm trong một phạm vi có thể quản lý, đồng thời vẫn giữ được các đặc tính của một hàm băm tốt.

Tính giờ theo đồng hồ

Modulo hữu ích trong xử lý thời gian, như chuyển số giờ lớn về định dạng thời gian tiêu chuẩn.

def convert_to_12_hour_format(hours):
    return hours % 12 or 12  # Ensure 0 maps to 12

# Example
print(convert_to_12_hour_format(13))  # Output: 1
print(convert_to_12_hour_format(24))  # Output: 12
print(convert_to_12_hour_format(36))  # Output: 12

Ở đây, toán tử modulo giúp “quấn” số giờ theo định dạng 12 giờ.

Phát triển game: Triển khai hệ thống lượt cho nhiều người chơi

Trong trò chơi theo lượt nhiều người chơi, ta có thể dùng modulo để xoay vòng lượt chơi.

players = ["Alice", "Bob", "Charlie"]
turns = 10

for turn in range(turns):
      current_player = players[turn % len(players)]
      print(f"Turn {turn + 1}: {current_player}'s move")
Turn 1: Alice's move
Turn 2: Bob's move
Turn 3: Charlie's move
Turn 4: Alice's move
Turn 5: Bob's move
Turn 6: Charlie's move
Turn 7: Alice's move
Turn 8: Bob's move
Turn 9: Charlie's move
Turn 10: Alice's move

Xác thực chữ số trong mã vạch

Nhiều hệ thống mã vạch dùng phép modulo để phát hiện lỗi trong các số được quét.

def is_valid_isbn13(isbn):
    digits = [int(d) for d in str(isbn)]
    checksum = sum(d * (1 if i % 2 == 0 else 3) for i, d in enumerate(digits))
    return checksum % 10 == 0

# Example ISBN Checksum validation
print(is_valid_isbn13(9780306406157))  # Output: True
print(is_valid_isbn13(9780306406158))  # Output: False
True
False

Kết luận

Toán tử modulo là một công cụ đa năng trong bộ công cụ của Python, vượt xa việc chỉ tính phần dư đơn thuần. Từ xác định số chẵn/lẻ đến triển khai các thuật toán phức tạp với mẫu chu kỳ, modulo giúp tạo ra các lời giải gọn gàng, tinh tế cho nhiều thách thức lập trình.

Bằng cách hiểu cả chức năng cơ bản lẫn hành vi tinh tế với các kiểu số khác nhau, bạn có thể tận dụng toán tử modulo để viết mã hiệu quả và dễ đọc hơn. Lần tới khi bạn cần triển khai logic liên quan đến chu kỳ, xoay vòng hoặc sự kiện tuần hoàn, hãy nhớ rằng toán tử modulo có thể là giải pháp hoàn hảo.

Nếu bạn muốn tìm hiểu thêm cách dùng Python cho các dự án của mình, hãy xem khóa học tương tác Giới thiệu về Khoa học Dữ liệu bằng Python của chúng tôi. 

Câu hỏi thường gặp về Modulo trong Python

Toán tử modulo hoạt động với số âm trong Python như thế nào?

Trong Python, khi dùng toán tử modulo với số âm, kết quả sẽ cùng dấu với số chia.

Có thể dùng toán tử modulo với số dấu phẩy động không?

Có, toán tử modulo hoạt động với số dấu phẩy động, nhưng cần lưu ý các sai số làm tròn nhỏ do cách biểu diễn số thực trong máy tính.

Toán tử modulo được dùng trong các ứng dụng thực tế như thế nào?

Toán tử modulo được dùng trong nhiều ứng dụng thực tế như hàm băm, tính thời gian theo đồng hồ và phát hiện lỗi như xác thực ISBN.

Vì sao toán tử modulo quan trọng trong lập trình?

Toán tử modulo rất quan trọng để giải các bài toán liên quan đến tính chu kỳ, phép chia và “quấn vòng”, khiến nó trở thành công cụ linh hoạt cho mã hiệu quả và thiết kế thuật toán.

Benito Martin

Tác giả

Benito Martin

Với vai trò Nhà sáng lập Martin Data Solutions và Nhà khoa học dữ liệu/ Kỹ sư ML & AI tự do, tôi sở hữu danh mục năng lực đa dạng về Hồi quy, Phân loại, Xử lý ngôn ngữ tự nhiên (NLP), LLM, RAG, Mạng nơ-ron, Phương pháp tổ hợp (Ensemble) và Thị giác máy tính.

  • Phát triển thành công nhiều dự án ML end-to-end, bao gồm làm sạch dữ liệu, phân tích, xây dựng mô hình và triển khai trên AWS và GCP, mang lại các giải pháp có tác động và khả năng mở rộng.
  • Xây dựng các ứng dụng web tương tác, có khả năng mở rộng bằng Streamlit và Gradio cho nhiều bài toán trong các ngành khác nhau.
  • Giảng dạy và cố vấn cho học viên về khoa học dữ liệu và phân tích, thúc đẩy sự phát triển nghề nghiệp của họ thông qua phương pháp học tập cá nhân hóa.
  • Thiết kế nội dung khóa học cho các ứng dụng retrieval-augmented generation (RAG) được điều chỉnh theo yêu cầu doanh nghiệp.
  • Viết các blog kỹ thuật AI & ML có sức ảnh hưởng, bao gồm các chủ đề như MLOps, cơ sở dữ liệu vector và LLM, đạt được mức độ tương tác đáng kể.

Trong mỗi dự án tôi đảm nhận, tôi luôn áp dụng các thực hành cập nhật trong kỹ thuật phần mềm và DevOps như CI/CD, linting mã, định dạng, giám sát mô hình, theo dõi thí nghiệm và xử lý lỗi mạnh mẽ. Tôi cam kết cung cấp các giải pháp hoàn chỉnh, chuyển hóa những hiểu biết từ dữ liệu thành chiến lược thực tiễn giúp doanh nghiệp phát triển và khai thác tối đa giá trị của khoa học dữ liệu, học máy và AI.

Chủ đề

Liên quan