Polynomial<T> — 多項式テンプレート
概要
Polynomial<T> は calx の多項式テンプレートクラスである。
係数型 T に double, Rational, Complex<double>
など任意の数値型を使用できる。
内部表現は昇べきの順: coeffs_[i] が $x^i$ の係数。
- 任意の係数型 —
doubleからRational(厳密計算) やComplex<T>まで - Horner 評価 — $O(n)$ で $p(x)$ を計算
- 多項式除算 — 商と剰余 (divmod)
- ユークリッド GCD — 多項式の最大公約因子
- 微分・積分 —
derivative(),integral() - 直交多項式 — Chebyshev, Legendre, Hermite, Laguerre, Bessel, Jacobi, Gegenbauer
- C++23 concepts —
PolynomialCoeffで型制約
ビルド
必要なヘッダ
#include <math/core/Polynomial.hpp>
ヘッダオンリー。リンクするライブラリは不要。
コンストラクタ
| シグネチャ | 説明 |
|---|---|
Polynomial() | 零多項式 |
Polynomial(const T& c) | 定数多項式 |
Polynomial(std::vector<T> coeffs) | 係数ベクトルから (昇べきの順) |
Polynomial(std::initializer_list<T> il) | 初期化子リストから |
Polynomial<double> p = {1.0, 2.0, 3.0}; // 1 + 2x + 3x^2
Polynomial<Rational> q = {Rational(1,2), Rational(3,4)}; // 1/2 + 3/4 x
アクセサ
| メンバ関数 | 説明 |
|---|---|
degree() | 次数 (零多項式は $-1$) |
isZero() | 零多項式か |
leadingCoefficient() | 主係数 $c_n$ |
constantTerm() | 定数項 $c_0$ |
operator[](i) const | $x^i$ の係数 (範囲外は $0$) |
operator[](i) | $x^i$ の係数への参照 (範囲外は自動拡張) |
coefficients() | 係数ベクトルへの参照 |
算術演算子
| 演算子 | 説明 |
|---|---|
p + q | 加算 |
p - q | 減算 |
p * q | 乗算 ($O(nm)$) |
p / q | 商 (多項式除算)。有理式モード時は RationalFunction を返す |
p % q | 剰余 (多項式除算) |
p.pow(n) | $p^n$ (二分累乗法) |
スカラーとの演算: p + c, c * p, p / c もサポート。
複合代入: +=, -=, *=, /=。
除算と剰余
auto [q, r] = p.divmod(d); // p = d * q + r, deg(r) < deg(d)
| 関数 | 説明 |
|---|---|
p.divmod(d) | 構造化束縛で商 q と剰余 r を返す |
p.quo(d) | 商のみ (常に多項式を返す。モードに依存しない) |
p / d | デフォルト: 商のみ。有理式モード時は RationalFunction |
p % d | 剰余のみ |
除算モード — operator/ の動作切り替え
Polynomial / Polynomial の戻り値型は、コンパイル時マクロで切り替えられる。
| モード | p / q の戻り値 | 用途 |
|---|---|---|
| デフォルト | Polynomial<T> (商) |
多項式環での演算。int / int と同じ意味 |
CALX_POLY_DIV_RATIONAL |
RationalFunction<T> (有理式) |
情報を失わない除算。数式処理向き |
切り替え方法 1: ソースコード内で定義
// RationalFunction.hpp をインクルードする前に定義
#define CALX_POLY_DIV_RATIONAL
#include <math/core/RationalFunction.hpp>
Polynomial<double> p = {1, 0, 1}; // x^2 + 1
Polynomial<double> q = {1, 1}; // x + 1
auto rf = p / q; // RationalFunction<double>: (x^2+1)/(x+1)
auto quot = p.quo(q); // Polynomial<double>: x - 1 (商が必要な場合)
切り替え方法 2: CMake で設定
# CMakeLists.txt
option(CALX_POLY_DIV_RATIONAL
"Polynomial / Polynomial returns RationalFunction" OFF)
if(CALX_POLY_DIV_RATIONAL)
add_compile_definitions(CALX_POLY_DIV_RATIONAL)
endif()
この設定でプロジェクト全体の operator/ の動作が切り替わる。
どちらのモードでも quo() と divmod() は常に多項式除算として使える。
評価
| 関数 | 説明 |
|---|---|
p(x) | Horner 法で $p(x)$ を計算。$O(n)$ |
p.evaluateEstrin(x) | Estrin 法 (並列性が高い) |
p(x) の x は T と異なる型でもよい (例: Polynomial<double> に Complex<double> を代入)。
x に多項式を渡すと 多項式合成 $p(q(x))$ になる。
compose(p, q) と等価。
Polynomial<double> p({1, 0, 1}); // 1 + x^2
Polynomial<double> q({0, 1, 1}); // x + x^2
auto r = p(q); // p(q(x)) = 1 + (x + x^2)^2 = 1 + x^2 + 2x^3 + x^4
合成後の次数は $\deg(p(q)) = \deg(p) \cdot \deg(q)$ となる。
微分・積分
| 関数 | 説明 |
|---|---|
p.derivative() | $p'(x)$ |
p.derivative(n) | $n$ 階微分 $p^{(n)}(x)$ |
p.integral() | 不定積分 $\int p(x)\,dx$ (定数項 = 0) |
definiteIntegral(p, a, b) | 定積分 $\int_a^b p(x)\,dx$ |
代数的操作
| 関数 | 説明 |
|---|---|
gcd(p, q) | ユークリッド GCD |
approximateGCD(p, q, tol) | 近似 GCD (浮動小数点向け) |
content(p) | 内容 (content) — 全係数の GCD |
primitivePart(p) | 原始部分 (primitive part) — $p / \text{content}(p)$ |
compose(p, q) | 合成 $p(q(x))$ |
monomial(c, n) | 単項式 $c \cdot x^n$ |
X<T>() | 変数 $x$ (次数 1 の多項式) |
因数分解・終結式
整数係数多項式の厳密な因数分解と、終結式・判別式を提供する。
ヘッダ math/core/Polynomial_factorization.hpp をインクルードする。
#include <math/core/Polynomial.hpp>
#include <math/core/Polynomial_factorization.hpp>
#include <math/core/FactoredInteger.hpp>
factorize() — 既約因子への分解
整数多項式 $f(x) \in \mathbb{Z}[x]$ を既約因子に分解する。
| シグネチャ | 説明 |
|---|---|
factorize(const Polynomial<T>& f) | $f = c \cdot \prod f_i^{e_i}$ に分解。FactoredInteger<Polynomial<T>> を返す |
係数型 T は int または int64_t。
パイプライン:
- content 抽出 — 全係数の GCD を定数因子として分離
- 有理根定理 — $f(b/a) = 0$ を $b \mid a_0$, $a \mid a_n$ の範囲で探索し、$(ax - b)$ の 1 次因子を全て取り除く
- Yun の無平方分解 — $\gcd(f, f')$ を用いて $f = \prod f_i^i$ ($f_i$ は無平方かつ互いに素)
- Kronecker 法 — 各無平方因子について $\deg f / 2 + 1$ 点での値の約数の組合せから Lagrange 補間で因子候補を構成
// x^4 - 1 = (x - 1)(x + 1)(x^2 + 1)
Polynomial<int> f = {-1, 0, 0, 0, 1};
auto factors = factorize(f);
for (size_t i = 0; i < factors.size(); ++i) {
std::cout << factors[i] << "^" << factors.exponent(i) << std::endl;
}
// (-1 + x)^1
// (1 + x)^1
// (1 + x^2)^1
上記は core 版 (ヘッダのみ、リンク不要) で、 Kronecker 法の組合せ上限 100,000 により $\deg f \lesssim 10$ が実用範囲。
高速版 (calx_factorize.lib)
calx_factorize をリンクすると、自動的に高速パイプラインに切り替わる:
- $\mathrm{GF}(p)$ 因数分解 — Cantor-Zassenhaus (DDF + EDF)
- Hensel lifting — 線形 + 多因子二分木 Hensel で $\mathbb{Z}[x]$ に引き上げ
- 因子復元 — $r \leq 12$: Zassenhaus 組合せ、$r > 12$: van Hoeij 格子復元 (LLL)
| 版 | 対応型 | リンク | 実用範囲 |
|---|---|---|---|
| core | int, int64_t | 不要 | $\deg \lesssim 10$ |
| pro | int, int64_t, Int, Rational | calx_factorize | $\deg \lesssim 100+$ |
Int 型は内部で int64_t に委譲 (全係数が 64-bit に収まる場合)。
Rational 型は分母の LCM で整数化してから Int パスに委譲する。
// CMake: target_link_libraries(your_target PRIVATE calx_factorize)
squareFreeFactorization() — Yun の無平方分解
| シグネチャ | 説明 |
|---|---|
squareFreeFactorization(const Polynomial<T>& f) | $f = c \cdot \prod f_i^i$ の分解のみ実行 (既約判定はしない) |
Yun のアルゴリズム (1976) を $\gcd(f, f')$ の subresultant PRS で実装。 重複因子を冪指数付きで分離する。既約性は保証しない。
整数多項式 GCD と擬剰余
| 関数 | 説明 |
|---|---|
intPolyGcd(a, b) | 整数多項式の GCD (subresultant PRS)。擬剰余と primitive 化を組合せ、係数の爆発を抑える |
pseudoRemainder(f, g) | 擬剰余 $\mathrm{lc}(g)^{\deg f - \deg g + 1} \cdot f \bmod g$。結果は必ず整数係数 |
擬剰余と通常の剰余の違い
通常の剰余は係数体 (体上での割り算) を仮定するので、整数係数では使えない:
$$f = q \cdot g + r, \quad \deg r < \deg g$$例: $f = x^2,\ g = 2x + 1$ を整数で割ろうとすると $q = \dfrac{x}{2} - \dfrac{1}{4}$ となり、商に分数が現れる ($\mathbb{Z}[x]$ では商も剰余も求まらない)。
擬剰余 (pseudo-remainder) は、先に $g$ の主係数の冪を掛けることで分数を回避する:
$$\mathrm{lc}(g)^{\deg f - \deg g + 1} \cdot f = q \cdot g + r, \quad \deg r < \deg g$$主係数 $\mathrm{lc}(g)$ を予め乗算しておくため、$g$ で割っても係数が整数のまま保たれる。
同じ例で: $\mathrm{lc}(g)^{2-1+1} = 2^2 = 4$ を掛けてから割ると
$$4 x^2 = (2x - 1)(2x + 1) + 1$$擬剰余 $r = 1$ (整数のみ)。
| 観点 | 通常の剰余 | 擬剰余 |
|---|---|---|
| 必要な代数構造 | 体 ($\mathbb{Q}, \mathbb{R}$ 等) | 環 ($\mathbb{Z}$ で OK) |
| 結果 | 厳密だが分数を含む | $\mathrm{lc}(g)^k$ 倍される |
| 用途 | 体上の Euclidean GCD | $\mathbb{Z}[x]$ の subresultant GCD、因数分解 |
calx の pseudoRemainder() は intPolyGcd() (整数多項式 GCD) のために用意されている —
整数係数のまま GCD を計算する subresultant PRS の基本演算である。
終結式・判別式
| 関数 | 説明 |
|---|---|
sylvesterMatrix(f, g) | $(m+n) \times (m+n)$ Sylvester 行列 |
resultant(f, g) | 終結式 $\mathrm{Res}(f, g) = \det(\mathrm{Sylvester}(f, g))$ |
discriminant(f) | 判別式 $\mathrm{Disc}(f) = (-1)^{n(n-1)/2} \mathrm{Res}(f, f') / a_n$ |
// f(x) = x^2 - 2 の判別式 = 4·1·2 = 8
Polynomial<int> f = {-2, 0, 1};
std::cout << discriminant(f) << std::endl; // 8
判別式が $0$ でなければ $f$ は無平方 (重根を持たない)。
直交多項式
漸化式により生成される古典的な直交多項式。
| 関数 | 多項式 |
|---|---|
chebyshevT<T>(n) | 第 1 種 Chebyshev $T_n(x)$ |
chebyshevU<T>(n) | 第 2 種 Chebyshev $U_n(x)$ |
legendre<T>(n) | Legendre $P_n(x)$ |
hermite<T>(n) | Hermite $H_n(x)$ (確率論者版) |
laguerre<T>(n) | Laguerre $L_n(x)$ |
bessel<T>(n) | Bessel 多項式 $y_n(x)$ |
jacobi<T>(n, α, β) | Jacobi $P_n^{(\alpha,\beta)}(x)$ |
gegenbauer<T>(n, λ) | Gegenbauer $C_n^{(\lambda)}(x)$ |
auto T5 = chebyshevT<double>(5);
std::cout << T5 << std::endl;
// 5x - 20x^3 + 16x^5
型特性
| 特性 | 説明 |
|---|---|
is_polynomial_v<T> | T が Polynomial<U> なら true |
使用例
#include <math/core/Polynomial.hpp>
#include <iostream>
using namespace calx;
int main() {
// 多項式の構築
Polynomial<double> p = {1.0, -3.0, 2.0}; // 1 - 3x + 2x^2
Polynomial<double> q = {1.0, 1.0}; // 1 + x
// 四則演算
std::cout << "p = " << p << std::endl;
std::cout << "q = " << q << std::endl;
std::cout << "p * q = " << p * q << std::endl;
// 除算
auto [quot, rem] = p.divmod(q);
std::cout << "p / q = " << quot << ", remainder = " << rem << std::endl;
// 評価 (Horner)
std::cout << "p(2.0) = " << p(2.0) << std::endl; // 3.0
// 微分・積分
std::cout << "p' = " << p.derivative() << std::endl; // -3 + 4x
std::cout << "∫p dx = " << p.integral() << std::endl;
// GCD
Polynomial<double> a = {-1.0, 0.0, 1.0}; // x^2 - 1 = (x-1)(x+1)
Polynomial<double> b = {-1.0, 1.0}; // x - 1
std::cout << "gcd(x^2-1, x-1) = " << gcd(a, b) << std::endl;
// 直交多項式
auto L3 = legendre<double>(3);
std::cout << "P_3(x) = " << L3 << std::endl;
}
関連する数学的背景
以下の記事では、Polynomial クラスの基盤となる数学的概念を解説している。
- 多項式の表現と基本演算 — 密/疎表現・加減乗除
- 多項式の GCD 計算 — ユークリッド・部分終結式アルゴリズム
- 因数分解(有限体上) — Berlekamp・Cantor-Zassenhaus 法
- 因数分解(整数上) — Hensel 持ち上げ・LLL 格子基底縮小