Cách triển khai các hàm tìm ước chung lớn nhất (UCLN) và bội chung nhỏ nhất (BCNN) bằng C++, C# và PHP. Dưới đây là mã nguồn và giải thích cho mỗi ngôn ngữ.


1. C++

Trong C++, chúng ta có thể sử dụng giải thuật Euclid để tìm UCLN và sau đó sử dụng công thức BCNN(a, b) = |a * b| / UCLN(a, b) để tìm BCNN.

C++
#include <iostream>
#include <numeric> // For std::gcd in C++17, or implement manually for older versions
#include <cmath>   // For std::abs

// Hàm tìm ước chung lớn nhất (UCLN) bằng giải thuật Euclid
long long gcd(long long a, long long b) {
    while (b) {
        a %= b;
        std::swap(a, b);
    }
    return std::abs(a); // UCLN luôn không âm
}

// Hàm tìm bội chung nhỏ nhất (BCNN)
long long lcm(long long a, long long b) {
    if (a == 0 || b == 0) {
        return 0; // BCNN của bất kỳ số nào với 0 là 0
    }
    return std::abs(a * b) / gcd(a, b);
}

int main() {
    long long num1 = 48;
    long long num2 = 18;

    std::cout << "UCLN(" << num1 << ", " << num2 << ") = " << gcd(num1, num2) << std::endl;
    std::cout << "BCNN(" << num1 << ", " << num2 << ") = " << lcm(num1, num2) << std::endl;

    long long num3 = 0;
    long long num4 = 10;
    std::cout << "UCLN(" << num3 << ", " << num4 << ") = " << gcd(num3, num4) << std::endl;
    std::cout << "BCNN(" << num3 << ", " << num4 << ") = " << lcm(num3, num4) << std::endl;

    long long num5 = -15;
    long long num6 = 25;
    std::cout << "UCLN(" << num5 << ", " << num6 << ") = " << gcd(num5, num6) << std::endl;
    std::cout << "BCNN(" << num5 << ", " << num6 << ") = " << lcm(num5, num6) << std::endl;

    return 0;
}

Giải thích:

  • gcd(long long a, long long b):
    • Sử dụng giải thuật Euclid: lặp lại việc lấy số dư của a cho b và sau đó gán b cho a và số dư cho b cho đến khi b bằng 0. Khi đó, a chính là UCLN.
    • std::abs(a) đảm bảo UCLN luôn không âm.
  • lcm(long long a, long long b):
    • Xử lý trường hợp a hoặc b là 0: BCNN của bất kỳ số nào với 0 là 0.
    • Sử dụng công thức BCNN(a, b) = |a * b| / UCLN(a, b). std::abs(a * b) được sử dụng để đảm bảo tích a * b luôn dương trước khi chia.

2. C#

Trong C#, cấu trúc tương tự như C++ có thể được áp dụng. Chúng ta sẽ tạo các phương thức tĩnh trong một lớp.

C#
using System;

public class MathOperations
{
    // Hàm tìm ước chung lớn nhất (UCLN) bằng giải thuật Euclid
    public static long Gcd(long a, long b)
    {
        while (b != 0)
        {
            long temp = b;
            b = a % b;
            a = temp;
        }
        return Math.Abs(a); // UCLN luôn không âm
    }

    // Hàm tìm bội chung nhỏ nhất (BCNN)
    public static long Lcm(long a, long b)
    {
        if (a == 0 || b == 0)
        {
            return 0; // BCNN của bất kỳ số nào với 0 là 0
        }
        return Math.Abs(a * b) / Gcd(a, b);
    }

    public static void Main(string[] args)
    {
        long num1 = 48;
        long num2 = 18;

        Console.WriteLine($"UCLN({num1}, {num2}) = {Gcd(num1, num2)}");
        Console.WriteLine($"BCNN({num1}, {num2}) = {Lcm(num1, num2)}");

        long num3 = 0;
        long num4 = 10;
        Console.WriteLine($"UCLN({num3}, {num4}) = {Gcd(num3, num4)}");
        Console.WriteLine($"BCNN({num3}, {num4}) = {Lcm(num3, num4)}");

        long num5 = -15;
        long num6 = 25;
        Console.WriteLine($"UCLN({num5}, {num6}) = {Gcd(num5, num6)}");
        Console.WriteLine($"BCNN({num5}, {num6}) = {Lcm(num5, num6)}");
    }
}

Giải thích:

  • Gcd(long a, long b):
    • Tương tự như C++, sử dụng giải thuật Euclid.
    • Math.Abs(a) để đảm bảo kết quả là không âm.
  • Lcm(long a, long b):
    • Xử lý trường hợp 0.
    • Sử dụng công thức BCNN(a, b) = |a * b| / UCLN(a, b). Math.Abs(a * b) đảm bảo tích luôn dương.

3. PHP

Trong PHP, chúng ta có thể định nghĩa các hàm độc lập để tìm UCLN và BCNN.

PHP
<?php

// Hàm tìm ước chung lớn nhất (UCLN) bằng giải thuật Euclid
function gcd($a, $b) {
    while ($b != 0) {
        $temp = $b;
        $b = $a % $b;
        $a = $temp;
    }
    return abs($a); // UCLN luôn không âm
}

// Hàm tìm bội chung nhỏ nhất (BCNN)
function lcm($a, $b) {
    if ($a == 0 || $b == 0) {
        return 0; // BCNN của bất kỳ số nào với 0 là 0
    }
    return abs($a * $b) / gcd($a, $b);
}

$num1 = 48;
$num2 = 18;

echo "UCLN($num1, $num2) = " . gcd($num1, $num2) . "\n";
echo "BCNN($num1, $num2) = " . lcm($num1, $num2) . "\n";

$num3 = 0;
$num4 = 10;
echo "UCLN($num3, $num4) = " . gcd($num3, $num4) . "\n";
echo "BCNN($num3, $num4) = " . lcm($num3, $num4) . "\n";

$num5 = -15;
$num6 = 25;
echo "UCLN($num5, $num6) = " . gcd($num5, $num6) . "\n";
echo "BCNN($num5, $num6) = " . lcm($num5, $num6) . "\n";

?>

Giải thích:

  • gcd($a, $b):
    • Tương tự như các ngôn ngữ khác, sử dụng giải thuật Euclid.
    • abs($a) đảm bảo UCLN không âm.
  • lcm($a, $b):
    • Xử lý trường hợp 0.
    • Sử dụng công thức BCNN(a, b) = |a * b| / UCLN(a, b). abs($a * $b) đảm bảo tích luôn dương.

Lưu ý chung cho tất cả các ngôn ngữ:

  • Kiểu dữ liệu: Sử dụng long long trong C++ và long trong C# để tránh tràn số khi tính toán với các số lớn. PHP tự động quản lý kiểu dữ liệu số nguyên, nhưng cần cẩn trọng với các giá trị quá lớn có thể vượt quá giới hạn của số nguyên hệ thống.
  • Giá trị tuyệt đối: Hàm UCLN luôn trả về một giá trị không âm. Do đó, việc sử dụng std::abs, Math.Abs, hoặc abs() là quan trọng khi trả về kết quả UCLN hoặc khi tính tích a * b trong BCNN để đảm bảo kết quả là dương.
  • Trường hợp đặc biệt với 0:
    • UCLN(a, 0) = |a| (hoặc UCLN(0, a) = |a|). Điều này được xử lý tự nhiên bởi giải thuật Euclid khi một trong các số là 0.
    • BCNN(a, 0) = 0 (hoặc BCNN(0, a) = 0). Đây là một trường hợp đặc biệt và được xử lý riêng trong các hàm lcm.