整数の最大公約数と最小公倍数の効率的計算手法

整数の最大公約数(GCD)と最小公倍数(LCM)は数論の基礎概念であり、暗号アルゴリズムや最適化処理で頻繁に利用される。GCDは共通の約数の最大値、LCMは共通の倍数の最小値を指す。これらの値は a × b = GCD(a,b) × LCM(a,b) の関係で結ばれ、GCDを先に求めることでLCMを効率的に導出できる。

標準ライブラリを活用する方法(C++17以降)

C++17では<numeric>ヘッダに標準化された計算関数が提供される。符号付き整数に対応し、オーバーフロー対策が施されている。

#include <iostream>
#include <numeric>
#include <cmath>

int main() {
    const long x_val = 42;
    const long y_val = 105;
    
    const auto common_divisor = std::gcd(x_val, y_val);
    const auto common_multiple = std::lcm(x_val, y_val);
    
    std::cout << "入力値: " << x_val << " と " << y_val << "\n";
    std::cout << "GCD結果: " << common_divisor << "\n";
    std::cout << "LCM結果: " << common_multiple << "\n";
    
    return 0;
}

ユークリッドの互除法による実装

除算剰余を反復的に計算する手法で、計算量はO(log min(a,b))。数学的根拠はgcd(a,b) = gcd(b, a mod b)の等価性にある。負の値には絶対値を適用し、ゼロ値の場合は特別な処理が必要。

#include <iostream>
#include <cstdlib>

// 反復処理による実装
long compute_gcd(long m, long n) {
    m = std::abs(m);
    n = std::abs(n);
    
    while (n != 0) {
        const long remainder = m % n;
        m = n;
        n = remainder;
    }
    return m;
}

long compute_lcm(long p, long q) {
    if (p == 0 || q == 0) return 0;
    return std::abs(p / compute_gcd(p, q) * q);
}

int main() {
    const long num1 = 72;
    const long num2 = 120;
    
    std::cout << "GCD(" << num1 << ", " << num2 << ") = " 
              << compute_gcd(num1, num2) << "\n";
    std::cout << "LCM(" << num1 << ", " << num2 << ") = " 
              << compute_lcm(num1, num2) << "\n";
}

ビット演算を用いた高速化手法(Steinのアルゴリズム)

除算をビットシフトで置き換えることで効率化。2で割り切れる場合の特殊処理が特徴で、特に大きな数値の処理で優位性を発揮する。

long stein_gcd(long u, long v) {
    if (u == 0) return v;
    if (v == 0) return u;
    
    const int common_twos = __builtin_ctzll(u | v);
    u >>= __builtin_ctzll(u);
    
    do {
        v >>= __builtin_ctzll(v);
        if (u > v) {
            const long temp = u;
            u = v;
            v = temp;
        }
        v -= u;
    } while (v != 0);
    
    return u << common_twos;
}

このアルゴリズムは符号なし整数で定義されるが、絶対値を適用することで符号付き整数にも拡張可能。ハードウェアのビット操作命令を直接利用するため、特定の環境で性能が向上する。

タグ: C++17 ユークリッドの互除法 Steinのアルゴリズム 最大公約数 最小公倍数

7月8日 20:53 投稿