Bài 4.1: Bài tập thực hành toán tử số học trong C++

Chào mừng bạn trở lại với chuỗi bài viết về C++! Sau khi đã làm quen với cách chương trình C++ hoạt động cơ bản và cách nhập/xuất dữ liệu, hôm nay chúng ta sẽ đi sâu vào một khía cạnh cốt lõi của mọi ngôn ngữ lập trình: các toán tử số học. Đây là những công cụ giúp chúng ta thực hiện các phép tính toán cơ bản, là nền tảng cho mọi chương trình phức tạp hơn.

Trong bài viết này, chúng ta sẽ không chỉ liệt kê các toán tử mà còn thực hành chúng thông qua nhiều ví dụ C++ cụ thể. Hãy chuẩn bị môi trường lập trình của bạn và cùng bắt tay vào nào!

1. Các Toán Tử Số Học Cơ Bản

C++ cung cấp các toán tử số học quen thuộc từ toán học:

  • +: Phép cộng
  • -: Phép trừ
  • *: Phép nhân
  • /: Phép chia
  • %: Phép chia lấy dư (Modulo)

Những toán tử này hoạt động với cả số nguyên (integer types như int, long) và số thực (floating-point types như float, double). Tuy nhiên, có một lưu ý quan trọng với phép chia (/) và phép chia lấy dư (%):

  • Phép chia /:
    • Nếu cả hai toán hạng là số nguyên, kết quả sẽ là phần nguyên của phép chia (phép chia nguyên - integer division).
    • Nếu ít nhất một toán hạng là số thực, kết quả sẽ là số thực (phép chia thực - floating-point division).
  • Phép chia lấy dư %:
    • Chỉ áp dụng cho các toán hạng là số nguyên. Kết quả là phần dư sau khi thực hiện phép chia nguyên.

Hãy xem ví dụ minh họa:

#include <iostream>

using namespace std;

int main() {
    int a = 10;
    int b = 3;
    double c = 10.0;
    double d = 3.0;

    cout << "--- Phep toan so nguyen ---" << endl;
    cout << "a = " << a << ", b = " << b << endl;
    cout << "a + b = " << a + b << endl;
    cout << "a - b = " << a - b << endl;
    cout << "a * b = " << a * b << endl;
    cout << "a / b = " << a / b << endl;
    cout << "a % b = " << a % b << endl;

    cout << "\n--- Phep toan so thuc ---" << endl;
    cout << "c = " << c << ", d = " << d << endl;
    cout << "c + d = " << c + d << endl;
    cout << "c - d = " << c - d << endl;
    cout << "c * d = " << c * d << endl;
    cout << "c / d = " << c / d << endl;

    cout << "\n--- Ket hop so nguyen va so thuc ---" << endl;
    cout << "a / d = " << a / d << endl;

    return 0;
}

Output:

--- Phep toan so nguyen ---
a = 10, b = 3
a + b = 13
a - b = 7
a * b = 30
a / b = 3
a % b = 1

--- Phep toan so thuc ---
c = 10, d = 3
c + d = 13
c - d = 7
c * d = 30
c / d = 3.33333

--- Ket hop so nguyen va so thuc ---
a / d = 3.33333

Giải thích code: Chúng ta khai báo các biến int (a, b) và double (c, d). Sau đó, thực hiện các phép toán cơ bản và in kết quả ra màn hình. Bạn có thể thấy rõ sự khác biệt giữa a / b (chia nguyên) và c / d (chia thực). Khi chia a (integer) cho d (double), C++ sẽ tự động chuyển đổi a thành double trước khi thực hiện phép chia, cho kết quả là số thực. Toán tử % chỉ dùng cho int.

2. Thứ Tự Ưu Tiên Của Toán Tử

Cũng giống như toán học, các toán tử trong C++ có thứ tự ưu tiên. Phép nhân (*), chia (/) và chia lấy dư (%) có độ ưu tiên cao hơn phép cộng (+) và trừ (-). Khi có nhiều toán tử cùng độ ưu tiên, chúng được thực hiện từ trái sang phải.

Để thay đổi thứ tự thực hiện hoặc để làm cho biểu thức dễ đọc hơn, bạn nên sử dụng dấu ngoặc đơn (). Mọi phép tính trong dấu ngoặc đơn sẽ được thực hiện trước.

Ví dụ:

#include <iostream>

using namespace std;

int main() {
    int x = 5;
    int y = 10;
    int z = 2;

    int kq1 = x + y * z;
    int kq2 = (x + y) * z;

    cout << "x + y * z = " << kq1 << endl;
    cout << "(x + y) * z = " << kq2 << endl;

    int kq3 = 20 / 4 * 2;
    cout << "20 / 4 * 2 = " << kq3 << endl;

    return 0;
}

Output:

x + y * z = 25
(x + y) * z = 30
20 / 4 * 2 = 10

Giải thích code: Ví dụ này cho thấy sự khác biệt khi có và không có dấu ngoặc đơn. result1 tính phép nhân trước, còn result2 tính phép cộng trong ngoặc trước. Với result3, phép chia và nhân có cùng ưu tiên, nên chúng được thực hiện từ trái sang phải (20 chia 4 được 5, sau đó 5 nhân 2 được 10). Luôn ưu tiên dùng dấu ngoặc đơn để làm rõ ý định của bạn!

3. Toán Tử Gán Kết Hợp

Trong lập trình, chúng ta thường thực hiện một phép toán lên một biến rồi gán lại kết quả cho chính biến đó. Ví dụ: x = x + 5;. C++ cung cấp các toán tử gán kết hợp (compound assignment operators) để viết tắt điều này:

  • +=: Cộng và gán (e.g., x += 5; tương đương x = x + 5;)
  • -=: Trừ và gán (e.g., y -= 2; tương đương y = y - 2;)
  • *=: Nhân và gán (e.g., z *= 3; tương đương z = z * 3;)
  • /=: Chia và gán (e.g., a /= 4; tương đương a = a / 4;)
  • %=: Chia lấy dư và gán (e.g., b %= 10; tương đương b = b % 10;)

Các toán tử này giúp code ngắn gọn và dễ đọc hơn.

Ví dụ:

#include <iostream>

using namespace std;

int main() {
    int tong = 100;

    cout << "Gia tri ban dau: " << tong << endl;

    tong += 50;
    cout << "Sau khi tong += 50: " << tong << endl;

    tong -= 20;
    cout << "Sau khi tong -= 20: " << tong << endl;

    tong *= 2;
    cout << "Sau khi tong *= 2: " << tong << endl;

    tong /= 10;
    cout << "Sau khi tong /= 10: " << tong << endl;

    int du = 17;
    du %= 5;
    cout << "17 % 5 = " << du << endl;

    return 0;
}

Output:

Gia tri ban dau: 100
Sau khi tong += 50: 150
Sau khi tong -= 20: 130
Sau khi tong *= 2: 260
Sau khi tong /= 10: 26
17 % 5 = 2

Giải thích code: Chúng ta bắt đầu với total = 100. Sau mỗi dòng sử dụng toán tử gán kết hợp, giá trị của total được cập nhật. Bạn có thể theo dõi sự thay đổi qua các dòng in ra màn hình. Toán tử /= thực hiện phép chia nguyên vì total10 đều là int.

4. Toán Tử Tăng/Giảm (Increment/Decrement)

Đây là hai toán tử rất phổ biến trong C++ và các ngôn ngữ khác, được sử dụng để tăng hoặc giảm giá trị của một biến lên 1 đơn vị.

  • ++: Toán tử tăng (increment)
  • --: Toán tử giảm (decrement)

Mỗi toán tử này lại có hai dạng:

  • Tiền tố (Prefix): Toán tử đứng trước tên biến (e.g., ++x, --y). Biến sẽ được tăng/giảm trước khi giá trị của biểu thức được sử dụng.
  • Hậu tố (Postfix): Toán tử đứng sau tên biến (e.g., x++, y--). Giá trị hiện tại của biến sẽ được sử dụng trong biểu thức, sau đó biến mới được tăng/giảm.

Sự khác biệt giữa tiền tố và hậu tố chỉ rõ ràng khi toán tử được sử dụng trong một biểu thức phức tạp hơn, ví dụ như khi gán giá trị cho một biến khác hoặc khi in ra màn hình. Nếu toán tử chỉ đứng một mình trong một câu lệnh (ví dụ: count++;), thì cả hai dạng tiền tố và hậu tố đều có tác dụng như nhau là tăng/giảm biến đi 1.

Hãy xem ví dụ kinh điển để thấy rõ sự khác biệt:

#include <iostream>

using namespace std;

int main() {
    int dem = 5;

    cout << "--- Hau to (Postfix) ---" << endl;
    cout << "Gia tri ban dau cua dem: " << dem << endl;
    cout << "Gia tri cua bieu thuc dem++: " << dem++ << endl;
    cout << "Gia tri cua dem sau dem++: " << dem << endl;

    cout << "\n--- Tien to (Prefix) ---" << endl;
    dem = 5;
    cout << "Gia tri ban dau cua dem: " << dem << endl;
    cout << "Gia tri cua bieu thuc ++dem: " << ++dem << endl;
    cout << "Gia tri cua dem sau ++dem: " << dem << endl;

    cout << "\n--- Phep giam (Decrement) ---" << endl;
    int gt = 10;
    cout << "Gia tri ban dau cua gt: " << gt << endl;
    cout << "Gia tri cua bieu thuc gt--: " << gt-- << endl;
    cout << "Gia tri cua gt sau gt--: " << gt << endl;

    gt = 10;
    cout << "Gia tri ban dau cua gt: " << gt << endl;
    cout << "Gia tri cua bieu thuc --gt: " << --gt << endl;
    cout << "Gia tri cua gt sau --gt: " << gt << endl;

    return 0;
}

Output:

--- Hau to (Postfix) ---
Gia tri ban dau cua dem: 5
Gia tri cua bieu thuc dem++: 5
Gia tri cua dem sau dem++: 6

--- Tien to (Prefix) ---
Gia tri ban dau cua dem: 5
Gia tri cua bieu thuc ++dem: 6
Gia tri cua dem sau ++dem: 6

--- Phep giam (Decrement) ---
Gia tri ban dau cua gt: 10
Gia tri cua bieu thuc gt--: 10
Gia tri cua gt sau gt--: 9
Gia tri ban dau cua gt: 10
Gia tri cua bieu thuc --gt: 9
Gia tri cua gt sau --gt: 9

Giải thích code: Ví dụ này làm rõ sự khác biệt giữa tiền tố và hậu tố.

  • Với count++: dòng cout << count++ << endl; trước tiên sử dụng giá trị hiện tại của count (là 5) để in ra màn hình, sau đó mới tăng count lên 6. Dòng tiếp theo in ra giá trị mới của count là 6.
  • Với ++count: dòng cout << ++count << endl; trước tiên tăng count lên 6, sau đó mới sử dụng giá trị mới này (là 6) để in ra màn hình. Dòng tiếp theo in ra giá trị mới của count vẫn là 6.

Toán tử giảm -- hoạt động theo nguyên tắc tương tự. Hiểu rõ sự khác biệt này là quan trọng khi bạn sử dụng các toán tử ++-- trong các biểu thức phức tạp hoặc trong vòng lặp.

5. Thực Hành Tổng Hợp

Để củng cố kiến thức, hãy thử một ví dụ kết hợp một vài toán tử để giải quyết một bài toán nhỏ: tính điểm trung bình của 3 môn học và làm tròn xuống số nguyên gần nhất.

#include <iostream>

using namespace std;

int main() {
    double d1 = 8.5;
    double d2 = 7.0;
    double d3 = 9.2;

    double tong_d = d1 + d2 + d3;
    cout << "Tong diem: " << tong_d << endl;

    double dtb = tong_d / 3.0;
    cout << "Diem trung binh (chua lam tron): " << dtb << endl;

    int dtb_lam_tron = static_cast<int>(dtb);
    cout << "Diem trung binh (lam tron xuong): " << dtb_lam_tron << endl;

    d1 += 0.5;
    cout << "Diem mon 1 sau khi cap nhat: " << d1 << endl;

    return 0;
}

Output:

Tong diem: 24.7
Diem trung binh (chua lam tron): 8.23333
Diem trung binh (lam tron xuong): 8
Diem mon 1 sau khi cap nhat: 9

Giải thích code: Chúng ta khai báo điểm của 3 môn dưới dạng double để có thể lưu giá trị thập phân. Tính tổng bằng phép cộng. Tính điểm trung bình bằng phép chia, sử dụng 3.0 để đảm bảo phép chia là phép chia thực. Sau đó, chúng ta sử dụng static_cast<int>() để ép kiểu kết quả trung bình sang int, điều này sẽ tự động làm tròn xuống (cắt bỏ phần thập phân). Cuối cùng, minh họa việc sử dụng toán tử += để cập nhật điểm.

Lời Khuyên Thực Hành

  • Hãy tự mình gõ lại các ví dụ trên, thay đổi các giá trị và xem kết quả thay đổi như thế nào.
  • Tự tạo ra các bài toán nhỏ của riêng bạn (ví dụ: tính diện tích hình chữ nhật, chuyển đổi nhiệt độ từ Celsius sang Fahrenheit) và sử dụng các toán tử số học để giải chúng.
  • Đặc biệt, hãy luyện tập với sự khác biệt giữa ++xx++ cho đến khi bạn hoàn toàn hiểu rõ.

Hiểu và sử dụng thành thạo các toán tử số học là bước đi vững chắc để bạn có thể viết được những chương trình tính toán phức tạp hơn sau này.

Comments

There are no comments at the moment.