Giải phương trình bậc 2 là một trong những bài tập lập trình C/C++ xuất hiện nhiều nhất trong các đề thi và bài tập ở trường. Bài viết này hướng dẫn từng bước cách xây dựng chương trình giải phương trình bậc 2 ax² + bx + c = 0, xử lý đầy đủ các trường hợp về nghiệm, kèm code hoàn chỉnh có thể chạy ngay.

Ôn Lại Lý Thuyết

Cho phương trình bậc 2: ax² + bx + c = 0 (a ≠ 0)

Biệt thức: Δ = b² - 4ac

Điều kiện Kết luận
Δ > 0 Phương trình có 2 nghiệm phân biệt: x₁ = (-b + √Δ) / 2a, x₂ = (-b - √Δ) / 2a
Δ = 0 Phương trình có nghiệm kép: x₁ = x₂ = -b / 2a
Δ < 0 Phương trình vô nghiệm (trong tập số thực)

Code C Giải Phương Trình Bậc 2

Trước khi viết code, hãy phân tích bài toán thành các bước nhỏ — đây là kỹ năng quan trọng mà sinh viên cần rèn luyện:

Luồng xử lý của chương trình:

Nhập a, b, c
    │
    ▼
a == 0? ──── Có ──→ Thông báo "không phải bậc 2", dừng
    │
   Không
    │
    ▼
Tính Δ = b² - 4ac
    │
    ├── Δ > 0 ──→ x1 = (-b + √Δ) / 2a
    │              x2 = (-b - √Δ) / 2a → In 2 nghiệm
    │
    ├── Δ = 0 ──→ x = -b / 2a → In nghiệm kép
    │
    └── Δ < 0 ──→ In "vô nghiệm"

Mỗi nhánh trong sơ đồ trên tương ứng với một khối if-else trong code. Khi đã vẽ được luồng xử lý, việc dịch sang C chỉ là bước cơ học.

#include <stdio.h>
#include <math.h>

int main() {
    double a, b, c;

    printf("Giai phuong trinh bac 2: ax^2 + bx + c = 0\n");
    printf("Nhap a: "); scanf("%lf", &a);
    printf("Nhap b: "); scanf("%lf", &b);
    printf("Nhap c: "); scanf("%lf", &c);

    /* Kiểm tra hệ số a */
    if (a == 0) {
        printf("He so a = 0, day khong phai phuong trinh bac 2!\n");
        return 0;
    }

    double delta = b * b - 4 * a * c;

    if (delta > 0) {
        double x1 = (-b + sqrt(delta)) / (2 * a);
        double x2 = (-b - sqrt(delta)) / (2 * a);
        printf("Delta = %.2f > 0\n", delta);
        printf("Phuong trinh co 2 nghiem phan biet:\n");
        printf("  x1 = %.4f\n", x1);
        printf("  x2 = %.4f\n", x2);
    } else if (delta == 0) {
        double x = -b / (2 * a);
        printf("Delta = 0\n");
        printf("Phuong trinh co nghiem kep: x1 = x2 = %.4f\n", x);
    } else {
        printf("Delta = %.2f < 0\n", delta);
        printf("Phuong trinh vo nghiem thuc.\n");
    }

    return 0;
}

Lưu ý khi biên dịch: Vì dùng hàm sqrt() từ thư viện <math.h>, bạn cần thêm cờ -lm khi biên dịch:

gcc phuong_trinh_bac2.c -o phuong_trinh_bac2 -lm

Ví Dụ Chạy Thử

Trường hợp 1 — 2 nghiệm phân biệt (a=1, b=-5, c=6):

Nhap a: 1
Nhap b: -5
Nhap c: 6
Delta = 1.00 > 0
Phuong trinh co 2 nghiem phan biet:
  x1 = 3.0000
  x2 = 2.0000

Trường hợp 2 — Nghiệm kép (a=1, b=-2, c=1):

Nhap a: 1
Nhap b: -2
Nhap c: 1
Delta = 0
Phuong trinh co nghiem kep: x1 = x2 = 1.0000

Trường hợp 3 — Vô nghiệm (a=1, b=0, c=1):

Nhap a: 1
Nhap b: 0
Nhap c: 1
Delta = -4.00 < 0
Phuong trinh vo nghiem thuc.

Giải Thích Chi Tiết Từng Bước Trong Code

Tại sao dùng double thay vì int hay float?

Nghiệm của phương trình bậc 2 thường là số thực có phần thập phân (ví dụ: x = 1.732…). Kiểu int chỉ lưu số nguyên nên sẽ mất dữ liệu. Kiểu float có độ chính xác khoảng 7 chữ số thập phân, đủ dùng nhưng dễ sai số. double có độ chính xác 15–16 chữ số — đây là lựa chọn tiêu chuẩn cho các bài toán số học trong C.

Tại sao scanf("%lf", ...) chứ không phải %f?

Khi đọc số thực kiểu double bằng scanf, bắt buộc dùng %lf (l = long, f = float). Ngược lại, printf có thể dùng %f hoặc %lf đều được — đây là điểm khác biệt tế nhị mà nhiều sinh viên hay nhầm.

Hàm sqrt() hoạt động thế nào?

sqrt(x) trả về căn bậc hai của x. Hàm này chỉ hoạt động đúng khi x >= 0 — đây là lý do chúng ta kiểm tra Δ trước, chỉ gọi sqrt(delta) khi delta >= 0. Gọi sqrt() với số âm không gây crash nhưng trả về NaN (Not a Number), dẫn đến kết quả sai.


Phiên Bản Dùng Hàm (Tách Biệt Logic)

Đây là cách viết chuyên nghiệp hơn, tách logic giải phương trình ra thành hàm riêng — phù hợp khi bạn cần tái sử dụng hoặc làm bài tập lớn.

Tại sao nên tách hàm? Giả sử bạn cần giải 100 phương trình bậc 2 trong cùng một chương trình — nếu không tách hàm, bạn sẽ phải copy-paste khối code 20 dòng tới 100 lần. Khi cần sửa logic, bạn phải sửa 100 chỗ. Với hàm solveQuadratic(), bạn chỉ sửa 1 chỗ duy nhất.

#include <stdio.h>
#include <math.h>

/* Giải phương trình bậc 2 ax^2 + bx + c = 0
 * Kết quả được lưu vào x1 và x2 (nếu có nghiệm)
 * Trả về: số nghiệm (0, 1, hoặc 2), -1 nếu a == 0
 */
int solveQuadratic(double a, double b, double c,
                   double *x1, double *x2) {
    if (a == 0) return -1;

    double delta = b * b - 4 * a * c;

    if (delta < 0) {
        return 0;
    } else if (delta == 0) {
        *x1 = *x2 = -b / (2 * a);
        return 1;
    } else {
        *x1 = (-b + sqrt(delta)) / (2 * a);
        *x2 = (-b - sqrt(delta)) / (2 * a);
        return 2;
    }
}

int main() {
    double a, b, c, x1, x2;

    printf("Nhap a, b, c: ");
    scanf("%lf %lf %lf", &a, &b, &c);

    int soNghiem = solveQuadratic(a, b, c, &x1, &x2);

    switch (soNghiem) {
        case -1:
            printf("a = 0, khong phai phuong trinh bac 2.\n");
            break;
        case 0:
            printf("Phuong trinh vo nghiem thuc.\n");
            break;
        case 1:
            printf("Nghiem kep: x = %.4f\n", x1);
            break;
        case 2:
            printf("x1 = %.4f, x2 = %.4f\n", x1, x2);
            break;
    }

    return 0;
}

Mối Liên Hệ Với Định Lý Viète

Sau khi tìm được hai nghiệm x₁ và x₂, bạn có thể kiểm tra nhanh kết quả bằng định lý Viète mà không cần thay lại vào phương trình:

  • Tổng hai nghiệm: x₁ + x₂ = -b/a
  • Tích hai nghiệm: x₁ × x₂ = c/a

Ví dụ kiểm tra: Phương trình x² - 5x + 6 = 0 có nghiệm x₁ = 3, x₂ = 2.

  • Tổng: 3 + 2 = 5 = -(-5)/1 ✓
  • Tích: 3 × 2 = 6 = 6/1 ✓

Bạn có thể thêm phần kiểm tra này vào chương trình để tự động xác nhận kết quả:

/* Kiểm tra bằng định lý Viète */
if (soNghiem == 2) {
    printf("Kiem tra Viet:\n");
    printf("  x1 + x2 = %.4f (phai bang %.4f)\n", x1 + x2, -b / a);
    printf("  x1 * x2 = %.4f (phai bang %.4f)\n", x1 * x2, c / a);
}

Các Lỗi Thường Gặp

1. Quên kiểm tra a = 0 Nếu a = 0, phương trình trở thành bậc 1 (bx + c = 0) — chương trình sẽ chia cho 0 gây lỗi. Luôn kiểm tra a trước khi tính toán.

2. So sánh số thực bằng == delta == 0 có thể thất bại do sai số dấu phẩy động. Trong thực tế nên dùng:

#define EPSILON 1e-9
if (fabs(delta) < EPSILON) { /* nghiệm kép */ }

3. Quên -lm khi biên dịch Hàm sqrt() thuộc thư viện toán học, cần link thêm bằng cờ -lm.


Bài Tập Mở Rộng

  1. Tổng hợp bậc 1 và bậc 2: Viết chương trình đọc a, b, c từ bàn phím. Nếu a = 0 thì giải phương trình bậc 1 (bx + c = 0), nếu a ≠ 0 thì giải phương trình bậc 2.

  2. Hiển thị nghiệm phức: Khi Δ < 0, thay vì in “vô nghiệm”, hãy in hai nghiệm phức dạng x = p ± qi với p = -b/(2a)q = √(|Δ|)/(2a).

  3. Giải nhiều phương trình: Cho phép người dùng nhập liên tiếp nhiều bộ (a, b, c) cho đến khi nhập a = b = c = 0 thì dừng.


Kết Luận

Chương trình giải phương trình bậc 2 trong C cần xử lý đủ 3 trường hợp của Δ. Điểm mấu chốt cần nhớ:

  • Luôn kiểm tra a ≠ 0 trước.
  • Dùng sqrt() từ <math.h> và biên dịch với -lm.
  • Nên tách logic vào hàm riêng để code sạch và dễ tái sử dụng.

Xem thêm