Trong bài này
Mai chuẩn bị 23 chiếc bánh cho nhóm học tập. Mỗi hộp chứa 5 chiếc, và nhóm chỉ giao hộp khi có đủ bánh. Mai cần tính số hộp, số bánh còn lại và quyết định có giao hay không.
Phép chia nguyên và chia dư giúp chia thành các nhóm
Mai xếp 23 chiếc bánh vào các hộp chứa 5 chiếc. Bạn hãy tính số hộp đầy và số bánh còn lại:
banh = 23
moi_hop = 5
print(banh // moi_hop)
print(banh % moi_hop)4 3
// là phép chia lấy phần nguyên (floor division). Với hai số nguyên dương ở đây, kết quả 4 cho biết số hộp đầy. % là phép chia lấy phần dư (modulo); kết quả 3 cho biết số bánh chưa xếp.
| Phần | Số bánh |
|---|---|
| Bốn hộp | 20 |
| Còn lại | 3 |
| Tổng | 23 |
Bốn hộp chứa 20 chiếc; cộng 3 chiếc còn lại được 23. Với số nguyên a và số nguyên khác không b, hệ thức a = (a // b) * b + a % b cũng đúng. Bạn có thể dùng hệ thức để kiểm tra kết quả.
Hãy so sánh ba phép chia cho cùng dữ liệu:
print(23 / 5)
print(23 // 5)
print(23 % 5)4.6 4 3
/ cho thương thông thường dạng float; // và % có công dụng khác. Nếu chia hết, phần dư bằng 0:
print(20 // 5)
print(20 % 5)4 0
Bạn không thể chia cho 0, kể cả khi dùng // hoặc %:
print(23 // 0)Lỗi khi chạy, ở dòng 1
ZeroDivisionError: integer division or modulo by zero
Python báo ZeroDivisionError. Hãy bảo đảm số chia khác không trước khi tính. Nếu cả hai toán hạng là số nguyên, // và % cho kết quả nguyên. Với số thực, kết quả có thể là số thực, chẳng hạn 7.0 // 2 cho 3.0.
Phép chia với số âm làm tròn thương xuống
Hãy chia âm bảy cho ba:
print(-7 / 3)
print(-7 // 3)
print(-7 % 3)-2.3333333333333335 -3 2
Thương thông thường nằm giữa -3 và -2. Python chọn số nguyên phía dưới là -3 cho //, không cắt về -2. Sau đó số dư là 2, vì -7 = (-3) * 3 + 2.
Thương-7 / 3 nằm giữa -3 và -2Làm tròn xuốngChọn -3Số dư-7 - (-3 × 3) = 2
Nếu số chia âm, số dư khác không mang dấu của số chia:
print(7 // -3)
print(7 % -3)-3 -2
Ở đây thương nguyên là -3 và dư là -2: 7 = (-3) * (-3) + (-2). Nếu phép chia hết, phần dư là 0. Quy tắc này áp dụng cho cả số nguyên dương và âm.
Khi cả số bị chia và số chia đều âm, thương thông thường lại dương. Hãy áp dụng cùng quy tắc cho -7 và -3:
print(-7 // -3)
print(-7 % -3)2 -1
Thương nguyên là 2 và số dư là -1, vì -7 = 2 * (-3) + (-1). Dư âm ở đây phù hợp với dấu của số chia. Đừng suy ra dấu số dư chỉ từ dấu của số bị chia.
Lũy thừa và thứ tự ưu tiên quyết định kết quả
Một hình vuông có cạnh 4 cm. Bạn có thể tính diện tích bằng cách nhân cạnh với chính nó:
canh = 4
print(canh ** 2)16
** là toán tử lũy thừa (exponentiation). canh ** 2 nghĩa là canh nhân với chính nó, nên kết quả là 16. Với số mũ nguyên dương 3, 2 ** 3 bằng 2 * 2 * 2.
Khi viết nhiều phép tính, Python dùng thứ tự ưu tiên (precedence). Mai mua hai chiếc bút, mỗi chiếc giá 4 nghìn, và một quyển vở giá 7 nghìn. Dòng đầu tính tổng tiền của Mai. Dòng sau tính tiền 7 chiếc bút và thêm 2 chiếc bút cùng giá 4 nghìn:
print(7 + 2 * 4)
print((7 + 2) * 4)15 36
Trong dòng đầu, phép nhân tính giá hai chiếc bút trước, rồi cộng giá vở, được 15 nghìn. Ngoặc ở dòng sau gộp số bút thành 7 + 2 chiếc trước khi nhân với 4, được 36 nghìn. Cặp ngoặc thay đổi phép tính, không chỉ trang trí code.
Trong các phép đã học, lũy thừa được tính trước nhân, chia, chia nguyên và chia dư. Nhóm nhân chia được tính trước cộng trừ. Với các phép cùng mức như nhân và chia, Python tính từ trái sang phải:
print(24 / 3 * 2)
print(2 + 3 ** 2)16.0 11
Dòng đầu chia trước rồi nhân; dòng sau tính 3 ** 2 trước khi cộng. Khi cần làm rõ ý định, bạn có thể dùng ngoặc ngay cả khi chúng không đổi kết quả. Riêng các phép lũy thừa nối tiếp được nhóm từ phải sang trái: 2 ** 3 ** 2 là 2 ** (3 ** 2).
Dấu âm đứng trước lũy thừa cũng cần chú ý:
print(-2 ** 2)
print((-2) ** 2)-4 4
Dòng đầu đổi dấu của 2 ** 2, được -4. Dòng sau bình phương số -2, được 4. Hãy đặt ngoặc khi cơ số âm để người đọc dễ nhận ra ý định.
Phép so sánh tạo giá trị đúng hoặc sai
Một phòng có 12 ghế. Nhóm 10 người có vừa nếu số người không vượt quá số ghế?
so_nguoi = 10
so_ghe = 12
print(so_nguoi <= so_ghe)True
Phép so sánh (comparison) kiểm tra quan hệ giữa hai giá trị. Kết quả là True hoặc False, hai giá trị bool đã gặp ở Bài 2. Vì 10 nhỏ hơn 12, kết quả ở đây là True.
| Toán tử | Câu hỏi |
|---|---|
== | Hai giá trị có bằng nhau? |
!= | Hai giá trị có khác nhau? |
< | Bên trái có nhỏ hơn? |
<= | Bên trái có nhỏ hơn hoặc bằng? |
> | Bên trái có lớn hơn? |
>= | Bên trái có lớn hơn hoặc bằng? |
Hãy xem trường hợp bằng nhau và khác nhau:
so_ghe = 12
print(so_ghe == 12)
print(so_ghe != 12)
print(so_ghe > 12)
print(so_ghe >= 12)True False False True
== kiểm tra bằng nhau, còn = gán giá trị vào biến. Hai dấu không thay thế được cho nhau. Ví dụ sau không phải cách đặt câu hỏi bằng nhau:
print(so_ghe = 12)Lỗi khi chạy, ở dòng 1
TypeError: 'so_ghe' is an invalid keyword argument for print()
Ở đây print() không nhận tham số tên so_ghe, nên báo TypeError. Để so sánh trong ngoặc, hãy viết so_ghe == 12 sau khi gán biến.
So sánh số và chuỗi chứa chữ số cần chú ý kiểu dữ liệu:
print(12 == "12")False
Kết quả là False vì số 12 và chuỗi "12" là hai giá trị khác kiểu. Nếu dòng nhập biểu diễn một số, hãy chuyển bằng int() trước khi so sánh số.
Toán tử logic kết hợp hoặc đảo điều kiện
Một chuyến tham quan cần ít nhất 10 người và có đủ 1 giáo viên. Cả hai yêu cầu phải đúng:
so_nguoi = 12
so_giao_vien = 1
print(so_nguoi >= 10 and so_giao_vien >= 1)True
and là toán tử logic (logical operator). Với hai điều kiện bool, kết quả đúng khi cả hai đúng. Nếu một điều kiện sai, kết quả sai. Chẳng hạn, 12 người nhưng không có giáo viên chưa đủ điều kiện.
Một thư viện mở phòng đọc khi có giáo viên hoặc thủ thư. Chỉ cần ít nhất một người trong hai nhóm:
co_giao_vien = False
co_thu_thu = True
print(co_giao_vien or co_thu_thu)True
Với hai giá trị bool, or cho True khi ít nhất một giá trị đúng, kể cả khi cả hai đúng. Nó cho False khi cả hai sai. and và or không mang cùng nghĩa.
Bạn cũng có thể đảo một kết quả:
da_dong = False
print(not da_dong)True
not đổi False thành True và đổi True thành False. Trong các ví dụ này, mỗi phần đưa vào toán tử logic là giá trị đúng sai. Python còn cho phép các giá trị khác, nhưng bạn chưa cần dùng chúng ở đây.
Python tính so sánh trước not, rồi and, rồi or. Bạn có thể đặt ngoặc để chỉ rõ nhóm điều kiện:
tuoi = 13
co_ve = True
print((tuoi >= 12) and co_ve)True
Điều kiện tuổi được kiểm tra trước, sau đó kết hợp với co_ve. Với and, nếu vế đầu sai, Python không cần tính vế sau; với or, nếu vế đầu đúng, Python cũng bỏ qua vế sau. Đây là cách đánh giá ngắn mạch (short-circuit evaluation).
so_chia = 0
print(so_chia != 0 and 12 / so_chia > 2)False
Vế đầu sai nên phép chia ở vế sau không chạy. Đổi thứ tự hai vế sẽ gây lỗi chia cho không. Khi viết điều kiện, hãy đặt phép kiểm tra bảo vệ trước phép tính cần được bảo vệ.
if chỉ chạy khối lệnh khi điều kiện đúng
Mai muốn báo khi có ít nhất 5 chiếc bánh để xếp một hộp:
7
banh = int(input())
if banh >= 5:
print("Du mot hop")
print("Da kiem tra")Du mot hop Da kiem tra
if mở một câu lệnh điều kiện (conditional statement). Python tính biểu thức sau if; nếu kết quả đúng, Python chạy khối bên dưới. Dấu : kết thúc dòng điều kiện. Bốn dấu cách đầu dòng đưa lệnh in vào khối lệnh (block) của if.
Với dữ liệu 7, cả hai dòng in đều chạy. Với dữ liệu 3, dòng thụt lề bị bỏ qua, còn Da kiem tra vẫn xuất hiện. Dòng này nằm ngoài khối vì không thụt lề.
NhậpĐọc số bánhKiểm traSố bánh ít nhất 5?Nếu đúngIn thông báo đủ một hộpTiếp tụcIn thông báo đã kiểm tra
Một khối có thể chứa nhiều lệnh. Các lệnh cùng thuộc khối phải thụt lề nhất quán:
banh = 6
if banh >= 5:
print("Du banh")
print("Chuan bi hop")
print("Ket thuc")Du banh Chuan bi hop Ket thuc
Nếu bỏ thụt lề sau if, Python không biết khối bắt đầu ở đâu:
if 6 >= 5:
print("Du banh")Lỗi khi chạy, ở dòng 2
IndentationError: expected an indented block after 'if' statement on line 1
Python báo IndentationError. Hãy thụt các lệnh thuộc khối bằng bốn dấu cách. Đừng đặt dấu : ở dòng lệnh bên trong; dấu này thuộc dòng mở khối.
else chọn hành động còn lại khi điều kiện sai
Mai cần thông báo cả khi chưa đủ bánh:
3
banh = int(input())
if banh >= 5:
print("Du banh")
else:
print("Chua du banh")Chua du banh
else đi cùng if, ngang lề với if và có dấu :. Nếu điều kiện đúng, Python chạy khối if; nếu sai, Python chạy khối else. Trong một lần thực hiện câu lệnh này, chỉ một trong hai khối chạy.
Hãy kiểm tra ranh giới 5: đúng bằng 5 vẫn thỏa banh >= 5. Nếu dùng banh > 5, chương trình sẽ báo thiếu dù vừa đủ. Giá trị sát ranh giới giúp phát hiện lỗi chọn dấu so sánh.
Một ví dụ khác kết hợp phép dư với hai nhánh:
-7
so = int(input())
if so % 2 == 0:
print("Chan")
else:
print("Le")Le
Một số nguyên chẵn chia cho 2 dư 0; số lẻ không có phần dư 0. Với -7, Python tính -7 % 2 bằng 1, nên chương trình in Le. else không viết thêm điều kiện; bạn sẽ học nhiều nhánh ở Bài 4.
Lỗi thường gặp
| Lỗi | Vì sao sai | Cách sửa |
|---|---|---|
Dùng / để đếm hộp đầy | / cho thương thông thường | Dùng // với số nguyên dương. |
| Cắt thương âm về không | // làm tròn xuống | Tìm số nguyên không lớn hơn thương. |
Chia hoặc lấy dư với 0 | Số chia không hợp lệ | Kiểm tra số chia trước phép tính. |
Nhầm = với == | Một dấu để gán, hai dấu để so sánh | Dùng == trong phép kiểm tra bằng nhau. |
Thiếu : sau if | Dòng mở khối chưa đúng cú pháp | Thêm : sau điều kiện. |
| Không thụt lề khối | Python không nhận ra lệnh thuộc nhánh | Thụt nhất quán bốn dấu cách. |
Dùng > khi cần bao gồm mức bằng | Giá trị ranh giới bị loại | Dùng >= nếu mức bằng được chấp nhận. |
Tóm tắt
//lấy thương làm tròn xuống;%lấy số dư tương ứng, với số chia khác không.**tính lũy thừa; ngoặc giúp xác định nhóm phép tính.- So sánh tạo
TruehoặcFalse;and,or,notkết hợp hoặc đảo điều kiện. ifchạy khối khi điều kiện đúng;elsechọn khối còn lại.- Dấu
:và thụt lề xác định cấu trúc nhánh. Hãy kiểm tra cả hai phía và ngay tại ranh giới.