Bài 31: Thực hành viết chương trình đơn giản Python

I. Kiến thức cần nhớ trước khi thực hành

1. Cấu trúc rẽ nhánh mở rộng if...elif...else

Khi có nhiều điều kiện lồng nhau, thay vì viết if...else bên trong else, Python cho phép viết gọn bằng elif:

Dạng lồng nhau (dài):

if <điều kiện 1>:
    <nhóm lệnh 1>
else:
    if <điều kiện 2>:
        <nhóm lệnh 2>
    else:
        <nhóm lệnh 3>

Dạng rút gọn với elif:

if <điều kiện 1>:
    <nhóm lệnh 1>
elif <điều kiện 2>:
    <nhóm lệnh 2>
else:
    <nhóm lệnh 3>

Cấu trúc if...elif...else có thể mở rộng với nhiều elif liên tiếp tuỳ theo số trường hợp cần xét.

2. Kỹ thuật gỡ lỗi với điểm dừng (Breakpoint)

Khi cần kiểm tra tính đúng đắn của chương trình – đặc biệt các vòng lặp – ta đặt điểm dừng (breakpoint) tại vị trí quan trọng. Mỗi lần chương trình dừng, quan sát giá trị các biến để xác nhận thuật toán đang chạy đúng.

Có thể kết hợp với việc in giá trị trung gian bằng lệnh print() để theo dõi chi tiết hơn.

3. Một số lưu ý quan trọng

  • Số $1$ không phải số nguyên tố và không phải hợp số.
  • Phép chia lấy phần nguyên // và phép chia lấy dư % rất hữu ích khi phân tích thừa số.
  • Khi giải phương trình bậc hai, cần xét đầy đủ tất cả trường hợp của $a$, $b$, $c$ (không chỉ trường hợp $a \neq 0$).
  • Hàm input() trả về xâu kí tự → cần chuyển kiểu bằng int() hoặc float().

II. Hướng dẫn thực hành

Nhiệm vụ 1: Kiểm tra số nguyên tố và phân tích thừa số nguyên tố

Yêu cầu: Nhập số tự nhiên $n$ từ bàn phím. Kiểm tra $n$ có phải số nguyên tố không. Nếu $n$ là hợp số, in ra kết quả phân tích $n$ thành tích các thừa số nguyên tố. Chú ý: số $1$ không là nguyên tố và cũng không là hợp số.

Ý tưởng thuật toán:

  • Dùng danh sách NT để lưu các thừa số nguyên tố.
  • Bắt đầu với $k = 2$, chia $n$ liên tục cho $k$. Khi $n$ không chia hết cho $k$ nữa thì tăng $k$ lên.
  • Nếu NT rỗng ($n = 1$): không là nguyên tố.
  • Nếu NT có đúng 1 phần tử: $n$ là nguyên tố.
  • Nếu NT có nhiều hơn 1 phần tử: $n$ là hợp số → in ra phân tích.

Chương trình đầy đủ:

# Nhập số tự nhiên từ bàn phím và kiểm tra n có phải là số nguyên tố hay không.
# Nếu n = 1 thì thông báo n không phải là số nguyên tố.
# Nếu n là hợp số thì in ra phân tích n thành tích các thừa số nguyên tố.
n = int(input("Nhập số tự nhiên n: "))
m = n
k = 2
NT = []
while m > 1:
    while m % k != 0:
        k = k + 1
    NT.append(k)
    m = m // k
count = len(NT)
if count == 0:
    print(n, "không là số nguyên tố")
elif count == 1:
    print(n, "là số nguyên tố")
else:
    print(n, "là hợp số")
    print(n, "=", end=" ")
    for i in range(count):
        if i < count - 1:
            print(NT[i], "x", end=" ")
        else:
            print(NT[i])

Kiểm thử bằng điểm dừng:

Đặt breakpoint tại dòng m = m // k để theo dõi sự thay đổi của các biến qua mỗi lần tìm được một thừa số nguyên tố. Với $n = 100$, bảng theo dõi giá trị trung gian:

k m n NT Ghi chú
2 100 100 [2] $100 \div 2 = 50$
2 50 100 [2, 2] $50 \div 2 = 25$
5 25 100 [2, 2, 5] $25 \div 5 = 5$
5 5 100 [2, 2, 5, 5] $5 \div 5 = 1$ → kết thúc

Kết quả: 100 là hợp số100 = 2 x 2 x 5 x 5

Thử với các giá trị khác:

Đầu vào Kết quả
$n = 1$ 1 không là số nguyên tố
$n = 7$ 7 là số nguyên tố
$n = 12$ 12 là hợp số, 12 = 2 x 2 x 3
$n = 100$ 100 là hợp số, 100 = 2 x 2 x 5 x 5

Nhiệm vụ 2: Giải phương trình bậc hai $ax^2 + bx + c = 0$

Yêu cầu: Nhập ba số thực $a$, $b$, $c$ từ bàn phím, tìm nghiệm phương trình. Xét đầy đủ mọi trường hợp.

Phân tích các trường hợp:

  • $a = b = c = 0$: phương trình có vô số nghiệm
  • $a = b = 0$, $c \neq 0$: phương trình vô nghiệm
  • $a = 0$, $b \neq 0$: phương trình bậc nhất, nghiệm duy nhất $x = -\dfrac{c}{b}$
  • $a \neq 0$: phương trình bậc hai, tính $\Delta = b^2 – 4ac$
    • $\Delta > 0$: hai nghiệm phân biệt $x_{1,2} = \dfrac{-b \pm \sqrt{\Delta}}{2a}$
    • $\Delta = 0$: nghiệm kép $x = \dfrac{-b}{2a}$
    • $\Delta < 0$: vô nghiệm

Thiết kế chương trình gồm 3 hàm:

  • NhapDL(): nhập ba số $a$, $b$, $c$
  • GiaiPT1(b, c): giải phương trình bậc nhất $bx + c = 0$
  • GiaiPT2(a, b, c): giải phương trình bậc hai (gọi GiaiPT1 khi $a = 0$)

Chương trình đầy đủ:

# Nhập từ bàn phím ba số thực a, b, c và tìm nghiệm của phương trình
# ax^2 + bx + c = 0.

def sqrt(x):
    return x ** 0.5

def NhapDL():
    s = input("Nhập ba số a, b, c cách nhau bởi dấu cách: ")
    snum = s.split()
    return float(snum[0]), float(snum[1]), float(snum[2])

def GiaiPT1(b, c):
    if b != 0:
        print("Phương trình có một nghiệm duy nhất:", round(-c / b, 1))
    elif c == 0:
        print("Phương trình có vô số nghiệm")
    else:
        print("Phương trình vô nghiệm")

def GiaiPT2(a, b, c):
    if a == 0:
        GiaiPT1(b, c)
    else:
        delta = b * b - 4 * a * c
        if delta > 0:
            x1 = (-b + sqrt(delta)) / (2 * a)
            x2 = (-b - sqrt(delta)) / (2 * a)
            print("Phương trình có hai nghiệm khác biệt")
            print("x1 =", round(x1, 1), "x2 =", round(x2, 1))
        elif delta == 0:
            x = (-b / (2 * a))
            print("Phương trình có nghiệm kép")
            print("x1,2 =", round(x, 1))
        else:
            print("Phương trình vô nghiệm")

# Chương trình chính
a, b, c = NhapDL()
GiaiPT2(a, b, c)

Kiểm thử với các bộ dữ liệu:

Đầu vào ($a$, $b$, $c$) $\Delta$ Kết quả
1 -3 2 $9 – 8 = 1 > 0$ Hai nghiệm: $x_1 = 2.0$, $x_2 = 1.0$
1 -2 1 $4 – 4 = 0$ Nghiệm kép: $x_{1,2} = 1.0$
1 1 1 $1 – 4 = -3 < 0$ Vô nghiệm
0 2 -6 Bậc nhất, nghiệm duy nhất: $3.0$
0 0 5 Vô nghiệm
0 0 0 Vô số nghiệm

III. Bài tập Luyện tập và Vận dụng

Luyện tập 1: Nhập số thực dương với kiểm tra dữ liệu

Câu 1. Viết chương trình yêu cầu nhập số thực dương $a$. Chương trình cần kiểm tra dữ liệu nhập như sau: Nếu số đã nhập nhỏ hơn hoặc bằng $0$ thì thông báo:

“Nhập sai, số $a$ phải lớn hơn $0$. Hãy nhập lại”

Chương trình chỉ dừng sau khi người dùng nhập đúng.

Lời giải:

a = float(input("Nhập số thực dương a: "))
while a <= 0:
    print("Nhập sai, số a phải lớn hơn 0. Hãy nhập lại")
    a = float(input("Nhập số thực dương a: "))
print("Số đã nhập hợp lệ: a =", a)

Giải thích: Sử dụng vòng lặp while để kiểm tra liên tục. Vòng lặp chỉ kết thúc khi người dùng nhập đúng giá trị $a > 0$.

Luyện tập 2: In bảng cửu chương

Câu 2. Viết chương trình in bảng cửu chương ra màn hình như sau:

  • Hàng thứ nhất in ra bảng nhân $1, 2, 3, 4, 5$.
  • Hàng thứ hai in ra bảng nhân $6, 7, 8, 9, 10$.

Lời giải:

# Hàng 1: bảng nhân 1 đến 5
for n in range(1, 6):
    print(f"Bảng nhân {n}:")
    for i in range(1, 11):
        print(f"  {n} x {i} = {n * i}")
    print()

# Hàng 2: bảng nhân 6 đến 10
for n in range(6, 11):
    print(f"Bảng nhân {n}:")
    for i in range(1, 11):
        print(f"  {n} x {i} = {n * i}")
    print()

Vận dụng 1: Đếm năm nhuận trong khoảng thời gian

Câu 1. Viết chương trình nhập hai số tự nhiên $Y_1$, $Y_2$ là số năm, $Y_2 > Y_1$. Tính xem trong khoảng thời gian từ năm $Y_1$ đến năm $Y_2$ có bao nhiêu năm nhuận. Áp dụng tính xem trong thế kỉ XXI có bao nhiêu năm nhuận.

Quy tắc năm nhuận:

  • Năm chia hết cho $4$ không chia hết cho $100$ → nhuận
  • Hoặc năm chia hết cho $400$ → nhuận

Lời giải:

Y1 = int(input("Nhập năm Y1: "))
Y2 = int(input("Nhập năm Y2: "))
dem = 0
for y in range(Y1, Y2 + 1):
    if (y % 4 == 0 and y % 100 != 0) or (y % 400 == 0):
        dem = dem + 1
print("Số năm nhuận từ", Y1, "đến", Y2, "là:", dem)

Áp dụng: Thế kỉ XXI (năm $2001$ đến $2100$), chạy chương trình với $Y_1 = 2001$, $Y_2 = 2100$ → kết quả: 24 năm nhuận.

Vận dụng 2: Tính ƯCLN bằng thuật toán Euclid (phép chia lấy dư)

Câu 2. Gọi $\text{ƯCLN}(a, b)$ là hàm Ước chung lớn nhất của hai số tự nhiên $a$, $b$. Dễ thấy ta có:

$$\text{ƯCLN}(a,\ b) = \text{ƯCLN}(b,\ a \% b) \quad \text{nếu } b > 0$$

$$\text{ƯCLN}(a,\ 0) = a$$

Từ đó hãy viết chương trình nhập hai số $a$, $b$ và tính $\text{ƯCLN}$ của $a$ và $b$.

Lời giải:

a = int(input("Nhập số a: "))
b = int(input("Nhập số b: "))
m, n = a, b
while n != 0:
    m, n = n, m % n
print("ƯCLN của", a, "và", b, "là:", m)

Kiểm thử:

Đầu vào Quá trình Kết quả
$a = 20$, $b = 16$ $(20, 16) \to (16, 4) \to (4, 0)$ $\text{ƯCLN} = 4$
$a = 12$, $b = 18$ $(12, 18) \to (18, 12) \to (12, 6) \to (6, 0)$ $\text{ƯCLN} = 6$
$a = 7$, $b = 3$ $(7, 3) \to (3, 1) \to (1, 0)$ $\text{ƯCLN} = 1$
Thầy Phạm Thành Danh

Thầy Phạm Thành Danh

(Người kiểm duyệt, ra đề)

Chức vụ: Trưởng ban biên soạn môn Tin Học THPT

Trình độ: Cử nhân Sư phạm Tin học, Chứng chỉ hạng II, Chứng chỉ Tin học, Ngoại ngữ B1

Kinh nghiệm: 8+ năm kinh nghiệm tại Trường THPT Thuận Hóa