Int デモ — 多倍長整数の威力
Int は符号付き任意精度の整数型である。
メモリが許す限り何桁でも正確に計算でき、
素数判定・冪剰余・拡張GCD などの数論アルゴリズムも組み込まれている。
このページでは 5 つのデモを通じて、多倍長整数ならではの威力を紹介する。 以下の出力はすべて calx で実際に計算したものである。 ソースコードはページ末尾に掲載しており、 calx をビルドすれば手元で同じ結果を確認できる。
Demo 1: フィボナッチ数 — 巨大整数の世界
フィボナッチ数 $F(n)$ は $F(0)=0,\; F(1)=1,\; F(n)=F(n-1)+F(n-2)$ で定義される数列で、 $n$ が大きくなると桁数が爆発的に増大する。 $F(10000)$ は 2092 桁の整数だが、calx なら わずか数ミリ秒で計算できる。
さらに $\gcd(F(m), F(n)) = F(\gcd(m, n))$ という美しい性質も検証する。
Demo 2: RSA 暗号のミニデモ
RSA 暗号は「大きな合成数の素因数分解が困難」という性質に基づく公開鍵暗号方式である。 ここではメルセンヌ素数 $M_{89}$ と $M_{107}$ を使い、 暗号化と復号が完全に一致することを示す。
isProbablePrime, powMod, inverseMod の
3 つの関数だけで暗号システムを実現できる。
Demo 3: メルセンヌ素数の検証
メルセンヌ素数 $M_p = 2^p - 1$ は、$p$ 自体が素数のときにのみ素数になりうる (必要条件であって十分条件ではない)。 $p = 11, 23, 29, \ldots$ のように $p$ が素数でも $M_p$ が合成数になる場合がある。
Demo 4: 巨大階乗と二項係数
階乗 $n!$ は $n$ とともに爆発的に増大する。 $1000!$ は 2570 桁の整数であり、末尾のゼロの数は $\lfloor 1000/5 \rfloor + \lfloor 1000/25 \rfloor + \lfloor 1000/125 \rfloor + \lfloor 1000/625 \rfloor = 249$ 個である。
Demo 5: 拡張ユークリッド互除法と冪剰余
拡張ユークリッド互除法は不定方程式 $ax + by = \gcd(a,b)$ の整数解を求める。 冪剰余 $a^n \bmod m$ は暗号や数論の基本演算である。 フェルマーの小定理 $a^{p-1} \equiv 1 \pmod{p}$ の検証と、 整数平方根も実演する。
拡張ユークリッド互除法: $ax + by = \gcd(a, b)$
冪剰余: $a^n \bmod m$
整数平方根
ソースコードと実行方法
このページの全出力は以下の C++ プログラムから生成された。 calx をビルドすれば、手元で同じ結果を確認できる。
example_int_demo.cpp (クリックで展開)
// Copyright (C) 2026 Kiyotsugu Arai
// SPDX-License-Identifier: LGPL-3.0-or-later
// example_int_demo.cpp
// 多倍長整数デモ: Int の威力を5つのシナリオで実演
#include <math/core/mp/Int.hpp>
#include <math/core/mp/Int/IntGCD.hpp>
#include <math/core/mp/Int/IntSqrt.hpp>
#include <math/core/mp/Int/IntModular.hpp>
#include <math/core/mp/Int/IntPrime.hpp>
#include <math/core/mp/Int/IntCombinatorics.hpp>
#include <iostream>
#include <iomanip>
#include <string>
#include <chrono>
#include <vector>
using namespace calx;
// ============================================================================
// Demo 1: フィボナッチ数 — 巨大整数の世界
// — F(1000) は 209 桁、F(10000) は 2092 桁の整数
// ============================================================================
static void demo_fibonacci() {
std::cout << "============================================================\n";
std::cout << " Demo 1: Fibonacci Numbers — The World of Giant Integers\n";
std::cout << "============================================================\n\n";
// 小さな値
std::cout << " F(10) = ";
{
Int a(0), b(1);
for (int i = 2; i <= 10; ++i) {
Int t = a + b;
a = std::move(b);
b = std::move(t);
}
std::cout << b << std::endl;
}
// F(100)
std::cout << " F(100) = ";
{
Int a(0), b(1);
for (int i = 2; i <= 100; ++i) {
Int t = a + b;
a = std::move(b);
b = std::move(t);
}
std::cout << b << std::endl;
}
// F(1000)
std::cout << "\n F(1000) = ";
{
Int a(0), b(1);
for (int i = 2; i <= 1000; ++i) {
Int t = a + b;
a = std::move(b);
b = std::move(t);
}
std::string s = b.toString();
// 先頭50桁 + ... + 末尾20桁
if (s.size() > 80) {
std::cout << s.substr(0, 50) << "..." << s.substr(s.size() - 20)
<< "\n (" << s.size() << " 桁)\n";
} else {
std::cout << s << "\n";
}
}
// F(10000) — 計時
{
auto start = std::chrono::high_resolution_clock::now();
Int a(0), b(1);
for (int i = 2; i <= 10000; ++i) {
Int t = a + b;
a = std::move(b);
b = std::move(t);
}
auto end = std::chrono::high_resolution_clock::now();
auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
std::string s = b.toString();
std::cout << "\n F(10000) = " << s.substr(0, 50) << "..."
<< s.substr(s.size() - 20)
<< "\n (" << s.size() << " 桁, " << us << " us)\n";
}
// フィボナッチ数の性質: gcd(F(m), F(n)) = F(gcd(m, n))
std::cout << "\n 性質: gcd(F(m), F(n)) = F(gcd(m, n))\n";
{
// F(12) と F(18) を計算
auto fib = [](int n) -> Int {
Int a(0), b(1);
for (int i = 2; i <= n; ++i) {
Int t = a + b;
a = std::move(b);
b = std::move(t);
}
return n == 0 ? a : b;
};
Int f12 = fib(12);
Int f18 = fib(18);
Int g = gcd(f12, f18);
Int f6 = fib(6);
std::cout << " F(12) = " << f12 << ", F(18) = " << f18 << "\n";
std::cout << " gcd(F(12), F(18)) = " << g << "\n";
std::cout << " F(gcd(12,18)) = F(6) = " << f6 << "\n";
std::cout << " 一致: " << ((g <=> f6) == 0 ? "YES" : "NO") << "\n";
}
std::cout << std::endl;
}
// ============================================================================
// Demo 2: RSA 暗号のミニデモ
// — 大きな素数・冪剰余・モジュラ逆元で暗号化と復号
// ============================================================================
static void demo_rsa() {
std::cout << "============================================================\n";
std::cout << " Demo 2: RSA Encryption — Mini Demo\n";
std::cout << "============================================================\n\n";
// メルセンヌ素数を使用 (Demo 3 で検証済み)
// M_89 = 2^89 - 1 (27桁の素数)
// M_107 = 2^107 - 1 (33桁の素数)
Int p = pow(Int(2), 89u) - Int(1);
Int q = pow(Int(2), 107u) - Int(1);
std::cout << " p = M_89 = " << p << " (" << p.toString().size() << " 桁)\n";
std::cout << " q = M_107 = " << q << " (" << q.toString().size() << " 桁)\n";
// 素数性の確認
std::cout << " p is prime: " << (isProbablePrime(p) ? "YES" : "NO") << "\n";
std::cout << " q is prime: " << (isProbablePrime(q) ? "YES" : "NO") << "\n\n";
// n = p * q
Int n = p * q;
std::cout << " n = p * q\n";
std::cout << " = " << n << "\n";
std::cout << " (" << n.toString().size() << " 桁)\n\n";
// phi(n) = (p-1)(q-1)
Int phi = (p - Int(1)) * (q - Int(1));
// 公開指数 e = 65537
Int e(65537);
std::cout << " 公開鍵: (n, e=" << e << ")\n";
// 秘密指数 d = e^-1 mod phi(n)
Int d = IntModular::inverseMod(e, phi);
std::cout << " 秘密鍵: d = " << d.toString().substr(0, 40) << "...\n";
std::cout << " (" << d.toString().size() << " 桁)\n\n";
// 暗号化: メッセージ m を暗号化
Int m(123456789);
std::cout << " 平文: m = " << m << "\n";
// c = m^e mod n
Int c = powMod(m, e, n);
std::cout << " 暗号文: c = " << c << "\n";
// 復号: m' = c^d mod n
Int m_dec = powMod(c, d, n);
std::cout << " 復号: m'= " << m_dec << "\n";
std::cout << " 一致: " << ((m <=> m_dec) == 0 ? "YES" : "NO") << "\n";
// もう少し大きなメッセージ
Int m2("314159265358979323846264338327950288");
std::cout << "\n 平文: m = " << m2 << "\n";
Int c2 = powMod(m2, e, n);
std::cout << " 暗号文: c = " << c2 << "\n";
Int m2_dec = powMod(c2, d, n);
std::cout << " 復号: m'= " << m2_dec << "\n";
std::cout << " 一致: " << ((m2 <=> m2_dec) == 0 ? "YES" : "NO") << "\n";
std::cout << std::endl;
}
// ============================================================================
// Demo 3: メルセンヌ素数の検証
// — 2^p - 1 が素数になる特別な p を検証
// ============================================================================
static void demo_mersenne() {
std::cout << "============================================================\n";
std::cout << " Demo 3: Mersenne Primes — 2^p - 1\n";
std::cout << "============================================================\n\n";
// 既知のメルセンヌ素数指数
int exponents[] = {2, 3, 5, 7, 13, 17, 19, 31, 61, 89, 107, 127};
// 素数でないもの (比較用)
int non_mersenne[] = {11, 23, 29, 37, 41, 43};
std::cout << " メルセンヌ素数 M_p = 2^p - 1:\n\n";
std::cout << std::setw(6) << "p" << " "
<< std::setw(8) << "素数?" << " "
<< "M_p の桁数" << " "
<< "M_p" << std::endl;
std::cout << std::string(70, '-') << std::endl;
for (int p : exponents) {
Int mp = pow(Int(2), static_cast<unsigned>(p)) - Int(1);
bool is_prime = isProbablePrime(mp);
std::string s = mp.toString();
std::string display = (s.size() <= 40) ? s
: s.substr(0, 30) + "..." + s.substr(s.size() - 5);
std::cout << std::setw(6) << p << " "
<< std::setw(8) << (is_prime ? "YES" : "no") << " "
<< std::setw(10) << s.size() << " "
<< display << std::endl;
}
std::cout << "\n 2^p - 1 が素数にならない p の例:\n";
for (int p : non_mersenne) {
Int mp = pow(Int(2), static_cast<unsigned>(p)) - Int(1);
bool is_prime = isProbablePrime(mp);
std::cout << " M_" << p << " = " << mp << " 素数: "
<< (is_prime ? "YES" : "NO") << std::endl;
}
std::cout << "\n M_127 は 39 桁の素数 — 1876 年にリュカが手計算で検証。\n";
std::cout << " コンピュータ登場以前に人間が検証した最大の素数である。\n";
std::cout << std::endl;
}
// ============================================================================
// Demo 4: 巨大階乗と二項係数
// — 1000! の桁数、C(100,50) の厳密値
// ============================================================================
static void demo_factorial_binomial() {
std::cout << "============================================================\n";
std::cout << " Demo 4: Factorial & Binomial Coefficients\n";
std::cout << "============================================================\n\n";
// 階乗
std::cout << " --- 階乗 n! ---\n";
for (int n : {10, 20, 50, 100, 1000}) {
auto start = std::chrono::high_resolution_clock::now();
Int fact = IntCombinatorics::factorial(Int(n));
auto end = std::chrono::high_resolution_clock::now();
auto us = std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
std::string s = fact.toString();
if (s.size() <= 50) {
std::cout << " " << std::setw(4) << n << "! = " << s << "\n";
} else {
std::cout << " " << std::setw(4) << n << "! = " << s.substr(0, 30)
<< "..." << s.substr(s.size() - 10) << " ("
<< s.size() << " 桁, " << us << " us)\n";
}
}
// 1000! の末尾ゼロの数
std::cout << "\n 1000! の末尾のゼロの数: ";
{
Int fact1000 = IntCombinatorics::factorial(Int(1000));
auto [q, count] = removeFactor(fact1000, Int(10));
std::cout << count << " 個\n";
std::cout << " (理論値: floor(1000/5)+floor(1000/25)"
"+floor(1000/125)+floor(1000/625) = "
<< (200 + 40 + 8 + 1) << ")\n";
}
// 二項係数
std::cout << "\n --- 二項係数 C(n, k) ---\n";
{
struct { int n, k; } cases[] = {{10, 5}, {20, 10}, {50, 25}, {100, 50}};
for (auto& [n, k] : cases) {
Int c = IntCombinatorics::binomial(Int(n), Int(k));
std::string s = c.toString();
std::cout << " C(" << std::setw(3) << n << ", " << std::setw(2)
<< k << ") = ";
if (s.size() <= 40) {
std::cout << s;
} else {
std::cout << s.substr(0, 30) << "... (" << s.size() << " 桁)";
}
std::cout << "\n";
}
}
// パスカルの三角形の性質
std::cout << "\n パスカルの三角形 (n=0..10):\n";
for (int n = 0; n <= 10; ++n) {
std::cout << std::string(static_cast<size_t>(30 - n * 3), ' ');
for (int k = 0; k <= n; ++k) {
Int c = IntCombinatorics::binomial(Int(n), Int(k));
std::cout << std::setw(5) << c << " ";
}
std::cout << "\n";
}
std::cout << std::endl;
}
// ============================================================================
// Demo 5: 拡張ユークリッド互除法と冪剰余
// — 不定方程式の解と巨大な冪の剰余
// ============================================================================
static void demo_number_theory() {
std::cout << "============================================================\n";
std::cout << " Demo 5: Extended GCD & Modular Exponentiation\n";
std::cout << "============================================================\n\n";
// 拡張ユークリッド互除法: ax + by = gcd(a, b) の解
std::cout << " --- 拡張ユークリッド互除法: ax + by = gcd(a, b) ---\n\n";
{
struct { int a, b; } cases[] = {{35, 15}, {240, 46}, {1071, 462}};
for (auto& [a, b] : cases) {
Int x, y;
Int g = IntGCD::extendedGcd(Int(a), Int(b), x, y);
std::cout << " " << a << " * (" << x << ") + "
<< b << " * (" << y << ") = " << g << "\n";
// 検算
Int check = Int(a) * x + Int(b) * y;
std::cout << " 検算: " << check << " = gcd(" << a << ", "
<< b << ") "
<< ((check <=> g) == 0 ? "OK" : "NG") << "\n\n";
}
}
// 巨大な冪剰余
std::cout << " --- 冪剰余: a^n mod m ---\n\n";
{
// 2^1000 mod (10^9 + 7)
Int mod(1000000007);
Int result = powMod(Int(2), Int(1000), mod);
std::cout << " 2^1000 mod (10^9+7) = " << result << "\n";
// フェルマーの小定理: a^(p-1) ≡ 1 (mod p)
Int p(1000000007);
Int a(314159265);
Int fermat = powMod(a, p - Int(1), p);
std::cout << "\n フェルマーの小定理: a^(p-1) mod p = 1\n";
std::cout << " " << a << "^(10^9+6) mod (10^9+7) = " << fermat << "\n";
std::cout << " (= 1: " << ((fermat <=> Int(1)) == 0 ? "YES" : "NO")
<< ")\n";
}
// 巨大整数の平方根
std::cout << "\n --- 整数平方根 ---\n\n";
{
// 10^100 の平方根 = 10^50
Int n = pow(Int(10), 100u);
Int s = IntSqrt::sqrt(n);
std::cout << " isqrt(10^100) = " << s << "\n";
std::cout << " (= 10^50: "
<< ((s <=> pow(Int(10), 50u)) == 0 ? "YES" : "NO") << ")\n";
// 2^256 の平方根
Int n2 = pow(Int(2), 256u);
Int s2 = IntSqrt::sqrt(n2);
std::cout << "\n isqrt(2^256) = " << s2 << "\n";
std::cout << " (= 2^128: "
<< ((s2 <=> pow(Int(2), 128u)) == 0 ? "YES" : "NO") << ")\n";
// 完全平方数判定
Int perfect = Int(12345678) * Int(12345678);
Int root;
bool is_sq = IntSqrt::isSquare(perfect, &root);
std::cout << "\n 12345678^2 = " << perfect << "\n";
std::cout << " isSquare: " << (is_sq ? "YES" : "NO")
<< ", sqrt = " << root << "\n";
}
std::cout << std::endl;
}
// ============================================================================
// main
// ============================================================================
int main() {
std::cout << "###########################################################\n";
std::cout << "# calx Int Demo — 多倍長整数の威力 #\n";
std::cout << "###########################################################\n\n";
demo_fibonacci();
demo_rsa();
demo_mersenne();
demo_factorial_binomial();
demo_number_theory();
std::cout << "###########################################################\n";
std::cout << "# 全デモ完了 #\n";
std::cout << "###########################################################\n";
return 0;
}
API の詳細は Int API リファレンス を参照のこと。
ビルドと実行
cd calx
mkdir build && cd build
cmake .. -G "Visual Studio 17 2022" -A x64
cmake --build . --config Release --target example-int-demo
examples\Release\example-int-demo.exe
計測環境
このページの計算時間は以下の環境で計測した参考値である。
- CPU: AMD Ryzen Threadripper PRO 5995WX (Zen 3)
- OS: Windows 11 Pro
- コンパイラ: MSVC 17.x (Visual Studio 2022), Release x64