Giải Tin Học 10 trang 148
Lời giải chi tiết SGK Lớp 10 · Môn Tin Há»c · Trang 148–149
Chào các em! Hai trang này thuộc chủ đề kiểm thử và sửa lỗi chương trình. Cô sẽ tóm tắt phần lý thuyết rồi giải chi tiết các bài tập trong mục Luyện tập và Vận dụng nhé.
Tóm tắt lý thuyết
Nội dung xoay quanh việc kiểm thử chương trình tính ƯCLN bằng thuật toán Euclid (trừ liên tiếp). Có hai cách kiểm soát lỗi:
- Cách 1 – In ra các giá trị trung gian: thêm biến đếm
kvà các lệnhprint()để quan sát sự thay đổi của các biến qua từng vòng lặp. - Cách 2 – Dùng điểm dừng (breakpoint): đặt điểm dừng tại dòng bắt đầu vòng lặp
while, chạy từng bước và ghi lại giá trị các biến vào bảng theo dõi.
Bảng theo dõi giá trị với m = 20, n = 16:
| Vòng lặp | m | n | Kết quả |
|---|---|---|---|
| 1 | 20 | 16 | |
| 2 | 4 | 16 | |
| 3 | 4 | 12 | |
| 4 | 4 | 8 | |
| Kết thúc lặp | 4 | 4 | 4 |
Kết luận: cả hai cách (in giá trị trung gian và đặt điểm dừng) đều hiệu quả để phát hiện và sửa lỗi.
LUYỆN TẬP
Bài 1: Lỗi ZeroDivisionError
Đề: Chương trình của em khi chạy phát sinh lỗi ngoại lệ ZeroDivisionError. Đó là lỗi gì và em sẽ xử lí lỗi này như thế nào?
Lời giải:
- ZeroDivisionError là lỗi xảy ra khi chương trình thực hiện phép chia (
/), chia lấy phần nguyên (//) hoặc lấy phần dư (%) mà mẫu số (số chia) bằng 0. Trong toán học phép chia cho 0 không xác định, nên Python báo lỗi ngoại lệ này.
- Cách xử lí: kiểm tra số chia trước khi thực hiện phép chia, hoặc dùng cấu trúc
try ... exceptđể bắt và xử lí ngoại lệ.
Ví dụ cách 1 – kiểm tra trước:
a = int(input("Nhập a: "))
b = int(input("Nhập b: "))
if b != 0:
print("a / b =", a / b)
else:
print("Lỗi: không thể chia cho 0!")
Ví dụ cách 2 – dùng try/except:
try:
print("a / b =", a / b)
except ZeroDivisionError:
print("Lỗi: không thể chia cho 0!")
Bài 2: Chương trình tính tổng hai số
Đề: Chương trình sau có lỗi không? Nếu có thì tìm và sửa lỗi.
m = input("Nhập số tự nhiên m: ")
n = input("Nhập số tự nhiên n: ")
print("Tổng hai số đã nhập là:", m+n)
Lời giải:
Chương trình CÓ lỗi về mặt logic (lỗi ngữ nghĩa).
- Hàm
input()luôn trả về kiểu xâu (string), không phải kiểu số. - Vì vậy phép
m + nkhông phải là phép cộng số học mà là phép nối hai xâu. - Ví dụ nhập m = 20, n = 16 thì kết quả in ra là
2016chứ không phải36.
Cách sửa: chuyển đổi dữ liệu nhập về kiểu số nguyên bằng int().
m = int(input("Nhập số tự nhiên m: "))
n = int(input("Nhập số tự nhiên n: "))
print("Tổng hai số đã nhập là:", m + n)
Sau khi sửa, nhập m = 20, n = 16 sẽ cho kết quả đúng là 36.
VẬN DỤNG
Bài 1: Chương trình sắp xếp dãy số
Đề: Chương trình sau có chức năng sắp xếp một dãy số cho trước. Hãy kiểm tra xem chương trình có lỗi không? Nếu có thì tìm và sửa lỗi.
A = [10,1,5,2,8,0,4]
for i in range(len(A)-1):
j = i
while j > 1 and A[j] < A[j-1]:
A[j],A[j-1] = A[j-1],A[j]
j = j - 1
print(A)
Lời giải:
Đây là thuật toán sắp xếp chèn (insertion sort). Chương trình CÓ hai chỗ sai về logic:
Lỗi 1 – Vòng lặp for bắt đầu sai chỉ số.
Với sắp xếp chèn, ta cần xét từng phần tử từ vị trí 1 trở đi để chèn về đúng chỗ trong phần đã sắp. Câu lệnh for i in range(len(A)-1) cho i chạy từ 0, đồng thời thiếu phần tử cuối. Cần cho i chạy từ 1 đến hết: range(1, len(A)).
Lỗi 2 – Điều kiện while j > 1 sai.
Để chèn phần tử về đúng vị trí, j phải có thể lùi tới tận vị trí 0, nghĩa là điều kiện phải là j > 0. Nếu để j > 1 thì phần tử không bao giờ được so sánh và đổi chỗ với phần tử đầu tiên (chỉ số 0), dẫn đến sắp xếp sai.
Chương trình đúng sau khi sửa:
A = [10,1,5,2,8,0,4]
for i in range(1, len(A)):
j = i
while j > 0 and A[j] < A[j-1]:
A[j],A[j-1] = A[j-1],A[j]
j = j - 1
print(A)
Kết quả khi chạy: [0, 1, 2, 4, 5, 8, 10] (dãy đã được sắp xếp tăng dần).
Giải thích thuật toán: với mỗi phần tử A[i], ta liên tục so sánh nó với phần tử liền trước. Nếu nó nhỏ hơn thì đổi chỗ và lùi về trước, lặp cho đến khi gặp phần tử nhỏ hơn hoặc về đầu dãy. Nhờ vậy phần đầu dãy luôn được giữ ở trạng thái đã sắp xếp.
Bài 2: Kiểm thử bằng bộ dữ liệu test
Đề: Để kiểm thử một chương trình, nếu chỉ bằng việc kiểm tra thông qua các bộ dữ liệu test thì có bảo đảm tìm ra hết lỗi của chương trình hay không? Vì sao?
Lời giải:
KHÔNG. Việc kiểm thử bằng các bộ dữ liệu test không bảo đảm tìm ra hết tất cả lỗi của chương trình.
Lí do:
- Mỗi bộ dữ liệu test chỉ kiểm tra được một số trường hợp cụ thể, trong khi số lượng tình huống đầu vào có thể là rất lớn hoặc vô hạn, không thể thử hết được.
- Một chương trình có thể chạy đúng với mọi bộ test đã chuẩn bị nhưng vẫn sai với những trường hợp đặc biệt mà ta chưa nghĩ tới (ví dụ: dãy rỗng, số 0, số âm, dữ liệu rất lớn, dữ liệu sai kiểu...).
- Như nhà khoa học máy tính Edsger Dijkstra từng nói: "Kiểm thử chương trình có thể chứng minh sự tồn tại của lỗi, nhưng không bao giờ chứng minh được sự vắng mặt của lỗi."
Vì vậy, ngoài kiểm thử bằng bộ test, ta nên kết hợp thêm các phương pháp khác như đọc lại mã, kiểm soát giá trị trung gian, đặt điểm dừng và lựa chọn các bộ test bao quát nhiều trường hợp tiêu biểu (kể cả trường hợp biên, trường hợp đặc biệt).
