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> // Để sử dụng cout và endl

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; // 10 + 3 = 13
    cout << "a - b = " << a - b << endl; // 10 - 3 = 7
    cout << "a * b = " << a * b << endl; // 10 * 3 = 30
    cout << "a / b = " << a / b << endl; // 10 / 3 = 3 (phep chia nguyen)
    cout << "a % b = " << a % b << endl; // 10 % 3 = 1 (phan du)

    cout << "\n--- Phep toan so thuc ---" << endl;
    cout << "c = " << c << ", d = " << d << endl;
    cout << "c + d = " << c + d << endl; // 10.0 + 3.0 = 13.0
    cout << "c - d = " << c - d << endl; // 10.0 - 3.0 = 7.0
    cout << "c * d = " << c * d << endl; // 10.0 * 3.0 = 30.0
    cout << "c / d = " << c / d << endl; // 10.0 / 3.0 = 3.333... (phep chia thuc)

    // Ket hop so nguyen va so thuc
    cout << "\n--- Ket hop so nguyen va so thuc ---" << endl;
    cout << "a / d = " << a / d << endl; // 10 (int) / 3.0 (double) = 3.333... (ket qua double)

    return 0;
}

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>

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

    int result1 = x + y * z; // Phep nhan y * z thuc hien truoc
    int result2 = (x + y) * z; // Phep cong (x + y) thuc hien truoc do co ngoac don

    cout << "x + y * z = " << result1 << endl; // 5 + 10 * 2 = 5 + 20 = 25
    cout << "(x + y) * z = " << result2 << endl; // (5 + 10) * 2 = 15 * 2 = 30

    int result3 = 20 / 4 * 2; // Phep chia va nhan co cung uu tien, thuc hien tu trai sang phai
    cout << "20 / 4 * 2 = " << result3 << endl; // (20 / 4) * 2 = 5 * 2 = 10

    return 0;
}

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>

int main() {
    int total = 100;

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

    total += 50; // total = total + 50;
    cout << "Sau khi total += 50: " << total << endl; // total la 150

    total -= 20; // total = total - 20;
    cout << "Sau khi total -= 20: " << total << endl; // total la 130

    total *= 2; // total = total * 2;
    cout << "Sau khi total *= 2: " << total << endl; // total la 260

    total /= 10; // total = total / 10; (phep chia nguyen)
    cout << "Sau khi total /= 10: " << total << endl; // total la 26

    int remainder = 17;
    remainder %= 5; // remainder = remainder % 5;
    cout << "17 % 5 = " << remainder << endl; // remainder la 2

    return 0;
}

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>

int main() {
    int count = 5;

    // Su dung hau to (postfix)
    cout << "--- Hau to (Postfix) ---" << endl;
    cout << "Gia tri ban dau cua count: " << count << endl; // count = 5
    cout << "Gia tri cua bieu thuc count++: " << count++ << endl; // In ra 5, sau do count tang len 6
    cout << "Gia tri cua count sau count++: " << count << endl; // count = 6

    cout << "\n--- Tien to (Prefix) ---" << endl;
    count = 5; // Reset ve 5 cho vi du tien to
    cout << "Gia tri ban dau cua count: " << count << endl; // count = 5
    cout << "Gia tri cua bieu thuc ++count: " << ++count << endl; // count tang len 6, sau do in ra 6
    cout << "Gia tri cua count sau ++count: " << count << endl; // count = 6

    // Phep giam -- cung tuong tu
    cout << "\n--- Phep giam (Decrement) ---" << endl;
    int value = 10;
    cout << "Gia tri ban dau cua value: " << value << endl; // value = 10
    cout << "Gia tri cua bieu thuc value--: " << value-- << endl; // In ra 10, sau do value giam xuong 9
    cout << "Gia tri cua value sau value--: " << value << endl; // value = 9

    value = 10; // Reset
    cout << "Gia tri ban dau cua value: " << value << endl; // value = 10
    cout << "Gia tri cua bieu thuc --value: " << --value << endl; // value giam xuong 9, sau do in ra 9
    cout << "Gia tri cua value sau --value: " << value << endl; // value = 9


    return 0;
}

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>

int main() {
    double score1 = 8.5;
    double score2 = 7.0;
    double score3 = 9.2;

    // Tinh tong diem su dung phep cong
    double sum_scores = score1 + score2 + score3;
    cout << "Tong diem: " << sum_scores << endl; // 8.5 + 7.0 + 9.2 = 24.7

    // Tinh diem trung binh su dung phep chia
    double average_score = sum_scores / 3.0; // Chia cho 3.0 (double) de co ket qua thuc
    cout << "Diem trung binh (chua lam tron): " << average_score << endl; // 24.7 / 3.0 = 8.233...

    // De lam tron xuong so nguyen, chung ta co the ep kieu (type casting) sang int
    int rounded_average = static_cast<int>(average_score);
    cout << "Diem trung binh (lam tron xuong): " << rounded_average << endl; // Ep kieu double sang int se cat bo phan thap phan

    // Su dung toan tu gán ket hop de cap nhat diem cua mon 1 (vi du)
    score1 += 0.5; // score1 = 8.5 + 0.5 = 9.0
    cout << "Diem mon 1 sau khi cap nhat: " << score1 << endl;

    return 0;
}

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.