Rational — 多倍長有理数

概要

Rational は calx の任意精度有理数型である。 内部表現は (分子 Int, 分母 Int) の対で、値 $x$ を次のように表す。

$$x = \frac{p}{q}, \quad q > 0, \quad \gcd(p, q) = 1$$

分母は常に正、分子と分母は常に約分済みの状態が維持される。 分母がゼロの場合は NaN として扱われる。

  • 任意精度 — 分子・分母ともに Int なので桁数に制限なし
  • 自動約分 — 演算のたびに GCD で約分し、正規化された状態を維持
  • NaN 安全 — ゼロ除算は NaN を返し、クラッシュしない
  • Int/int との混合演算Rational + Int, Rational * int が自然に書ける

コンストラクタ

シグネチャ説明
Rational()デフォルト構築。値は 0/1
Rational(int num, int den = 1)int の分子/分母から構築 (自動約分)
Rational(const Int& num)Int から構築 (分母 = 1)
Rational(const Int& num, const Int& den, bool doReduce = true)Int の分子/分母から構築
Rational(Int&& num, Int&& den, bool doReduce = true)ムーブ版
Rational(std::string_view str, int base = 10)文字列 "p/q" 形式から構築
Rational(double value)double から正確な有理数に変換
Rational(float value)float から正確な有理数に変換
Rational(const Float& value)多倍長浮動小数点から正確な有理数に変換

doReduce = false を指定すると約分をスキップする (呼び出し側が既に約分済みであることを保証する場合)。

アクセサ

メンバ関数説明
const Int& numerator() const分子を返す
const Int& denominator() const分母を返す (常に正)
friend void swap(Rational& a, Rational& b) noexcept2 つの Rational オブジェクトを交換

算術演算子

四則演算

演算子説明
Rational + Rational加算 ($\frac{a}{b} + \frac{c}{d} = \frac{ad+bc}{bd}$, 約分)
Rational - Rational減算
Rational * Rational乗算 ($\frac{a}{b} \times \frac{c}{d} = \frac{ac}{bd}$, 約分)
Rational / Rational除算 ($\frac{a}{b} \div \frac{c}{d} = \frac{ad}{bc}$, 約分)
Rational % Rational剰余

Int および int との混合演算もすべてサポート:

  • Rational + Int, Int + Rational
  • Rational * int, int * Rational
  • 複合代入: +=, -=, *=, /=

その他の演算

演算説明
-r符号反転
++r, r++インクリメント
--r, r--デクリメント
r.pow(n)$r^n$ (int 指数)
pow(r, e)$r^e$ (Int 指数)
r << n$r \times 2^n$
r >> n$r / 2^n$

比較演算子

C++20 三方比較 (<=>) をサポート。std::partial_ordering を返す (NaN を考慮)。

比較説明
Rational <=> Rational三方比較
Rational == Rational等値比較
Rational <=> IntInt との比較
Rational <=> intint との比較

状態確認

メンバ関数説明
isZero()値が 0 か
isNonZero()値が 0 でないか
isPositive()値が正か
isNegative()値が負か
isNonPositive()値が 0 以下か
isNonNegative()値が 0 以上か
isOne()値が 1 か
isInteger()分母が 1 か (整数値)
isNaN()NaN 状態か
reduce()手動で約分を実行し正規化する。コンストラクタの doReduce=false で約分を省略した場合に、後から呼び出す。変更があれば true を返す

数学関数

関数説明
abs(x)絶対値 $|x|$
inv(x)逆数 $1/x$
square(x)$x^2$
sgn(x)符号 ($-1, 0, 1$)
floor(x)$\lfloor x \rfloor$ (Int を返す)
ceil(x)$\lceil x \rceil$ (Int を返す)
trunc(x)ゼロ方向の切り捨て (Int を返す)
round(x)四捨五入 (Int を返す)
frac(x)小数部分 $x - \lfloor x \rfloor$
height(x)高さ $\max(|p|, |q|)$
gcd(x, y)有理数の GCD
mediant(a, b)中間分数 (mediant) $\frac{p_a + p_b}{q_a + q_b}$
r.doubled()$2r$
r.halved()$r/2$
r.reciprocal()逆数 $q/p$。$O(1)$。ゼロの逆数は NaN
conj(x)共役 (実有理数では自身を返す。Complex<Rational> との互換性のために存在)

連分数

関数説明
r.toContinuedFraction()連分数展開 $[a_0; a_1, a_2, \ldots]$ を返す
Rational::fromContinuedFraction(cf)連分数から Rational を復元
Rational r(355, 113);
auto cf = r.toContinuedFraction();  // [3; 7, 16]
Rational r2 = Rational::fromContinuedFraction(cf);  // 355/113

数論関数

関数説明
harmonicNumber(n)調和数 $H_n = 1 + \frac{1}{2} + \cdots + \frac{1}{n}$
dedekindSum(h, k)デデキント和 $s(h, k)$
reconstructRational(a, m, N, D)$a \bmod m$ から $p/q$ を復元 ($|p| \le N, 0 < q \le D$)
mod(x, m)有理数の mod: $\frac{p}{q} \bmod m = p \cdot q^{-1} \bmod m$

有理数列挙

関数説明
nextMinimal(x)Stern-Brocot 順で次の正有理数
nextCalkinWilf(x)Calkin-Wilf 列で次の正有理数
fareyNeighbors(x, Q)Farey 数列 $F_Q$ における左右近傍
simplestBetween(a, b)開区間 $(a, b)$ 内の最小高さ有理数

数学定数

以下の定数は Rational 値として正確に計算される。計算済みの値はスレッドセーフな静的キャッシュに保存される。

関数説明
bernoulli(n)Bernoulli 数 $B_n$ (標準再帰式)
stirlingCoefficient(k)Stirling 近似の係数 $c_k$
Rational b0 = bernoulli(0);   // 1
Rational b1 = bernoulli(1);   // -1/2
Rational b2 = bernoulli(2);   // 1/6
Rational b4 = bernoulli(4);   // -1/30
Rational b6 = bernoulli(6);   // 1/42

変換

関数説明
toDouble()double に変換
toFloat()float に変換
toMpFloat(precision)Float に変換 (指定精度)
toString(base)"p/q" 形式の文字列
toDecimal(digits)10 進小数文字列 (指定桁数)
explicit operator int()int に変換 (切り捨て)
explicit operator double()double に変換
Rational& operator=(double value)double からの代入
Rational& operator=(float value)float からの代入

ストリーム入出力

Rational r(22, 7);
std::cout << r;  // 出力: 22/7

Rational s;
std::cin >> s;   // 入力: "3/4" → Rational(3, 4)

使用例

#include <math/core/mp/Rational.hpp>
#include <iostream>
using namespace calx;

int main() {
    // 基本的な四則演算 (自動約分)
    Rational a(1, 3);   // 1/3
    Rational b(1, 6);   // 1/6
    std::cout << a + b << std::endl;  // 1/2

    // Bernoulli 数
    for (int n = 0; n <= 10; n += 2)
        std::cout << "B(" << n << ") = " << bernoulli(n) << std::endl;

    // 連分数展開
    Rational pi_approx(355, 113);
    auto cf = pi_approx.toContinuedFraction();  // [3; 7, 16]

    // 調和数
    Rational h10 = harmonicNumber(10);  // 7381/2520
    std::cout << "H(10) = " << h10 << " = " << h10.toDecimal(15) << std::endl;

    // NaN 安全
    Rational nan = Rational(1, 0);
    std::cout << nan << std::endl;  // NaN
}