RationalFunction — 有理式
概要
有理式 (RationalFunction<T>) は 2 つの多項式の商 $f(x) = P(x)/Q(x)$ を表す型である。
分子 $P$・分母 $Q$ をそれぞれ Polynomial<T> として保持し、
構築時に既定で 最大公約因子 (GCD) を自動約分する。
- 体としての演算 — 有理式は体をなし、四則 ($+ - \times \div$) が閉じている。
- 微分・合成・冪 — 商の微分公式・関数合成・整数冪をサポートする。
- 部分分数分解 — 単純極について Heaviside 法で $\sum_k A_k/(x - r_k)$ に分解する。
- 極零相殺 — 近似 GCD により伝達関数の余分な極零対を相殺し最小実現を得る。
係数型 $T$ は double・float のほか多倍長 Float・有理数 Rational なども使える
(部分分数分解・極零など根を扱う関数は浮動小数型が前提)。
ビルド
#include <math/core/RationalFunction.hpp> // 有理式 本体
#include <math/core/RationalFunction_partialFractions.hpp> // 部分分数分解・極・零・留数
ヘッダオンリー。リンクするライブラリは不要。RationalFunction.hpp は
Polynomial.hpp のみに依存する。
構築
| コンストラクタ | 意味 |
|---|---|
RationalFunction() | 零有理式 $0/1$ |
RationalFunction(const T& c) | 定数 $c/1$ |
RationalFunction(const Polynomial<T>& p) | 多項式を分子に $P(x)/1$ |
RationalFunction(const Polynomial<T>& num, const Polynomial<T>& den, bool doSimplify = true) | 分子・分母を指定 (既定で GCD 約分) |
RationalFunction(std::initializer_list<T> num, std::initializer_list<T> den, bool doSimplify = true) | 係数リスト (昇べき順) から構築 |
パラメータ:
| 引数 | 型 | 説明 |
|---|---|---|
num, den | std::initializer_list<T> / Polynomial<T> | 分子・分母。係数リストは昇べき順 ({c0, c1, c2, ...} = $c_0 + c_1 x + c_2 x^2 + \cdots$) |
doSimplify | bool | true (既定) なら GCD で共通因子を約分。false で約分せず保持 |
約分により次数が下がる例 ($\frac{x^2 - 1}{x - 1} = x + 1$):
// (x^2 - 1) / (x - 1) 昇べき係数: {-1,0,1} / {-1,1}
RationalFunction<double> f({-1, 0, 1}, {-1, 1});
std::cout << f.toString(); // 実行結果: x+1 (共通因子 (x-1) を約分)
std::cout << f(3.0); // 実行結果: 4
アクセサ・約分
| メンバ | 戻り値 | 説明 |
|---|---|---|
numerator() | const Polynomial<T>& | 約分後の分子多項式 |
denominator() | const Polynomial<T>& | 約分後の分母多項式 |
numeratorDegree() | int | 分子の次数 |
denominatorDegree() | int | 分母の次数 |
isZero() | bool | 分子が零なら true |
simplify() | bool | 共通 GCD 因子を約分。約分が起きれば true |
approximateSimplify(double tol = 1e-10) | bool | 近似 GCD でほぼ共通な因子を約分 (浮動小数の極零相殺向け) |
chopSmallValues(const T& eps) | void | (浮動小数型) eps 未満の係数を 0 にして約分 |
四則演算
有理式同士、有理式とスカラー $c$、有理式と多項式の間で四則が定義される (いずれも結果を自動約分)。
複合代入 (+= -= *= /=) と単項 - も用意する。
| 演算 | 規則 |
|---|---|
f + g | $\dfrac{P_1}{Q_1} + \dfrac{P_2}{Q_2} = \dfrac{P_1 Q_2 + P_2 Q_1}{Q_1 Q_2}$ (分母一致時は最適化) |
f - g | $\dfrac{P_1 Q_2 - P_2 Q_1}{Q_1 Q_2}$ |
f * g | $\dfrac{P_1 P_2}{Q_1 Q_2}$ |
f / g | $\dfrac{P_1 Q_2}{Q_1 P_2}$ |
f == g | $P_1 Q_2 = P_2 Q_1$ で判定 (交差乗算) |
RationalFunction<double> f({1}, {1, 1}); // 1/(1+x)
RationalFunction<double> g({0, 1}, {1, 1}); // x/(1+x)
std::cout << (f + g).toString(); // 実行結果: 1 (1/(1+x) + x/(1+x) = 1)
std::cout << (f * g).toString(); // 実行結果: x/(x^2+2x+1)
std::cout << (f / g).toString(); // 実行結果: 1/x
評価・合成
| 呼び出し | 戻り値 | 説明 |
|---|---|---|
f(x) (スカラー x) | U | $P(x)/Q(x)$ を数値評価 |
f(p) (多項式 p) | RationalFunction<T> | 多項式を代入して合成 |
compose(f, g) | RationalFunction<T> | 有理式同士の合成 $f(g(x))$ |
RationalFunction<double> f({1}, {1, 1}); // 1/(1+x)
RationalFunction<double> g({0, 1}, {1, 1}); // x/(1+x)
auto h = compose(f, g); // f(g(x)) = 1 / (1 + x/(1+x)) = (1+x)/(1+2x)
std::cout << h.toString(); // 実行結果: (x+1)/(2x+1)
std::cout << h(1.0); // 実行結果: 0.666666666666667 (= 2/3)
微分・逆数・冪
| メンバ | 戻り値 | 説明 |
|---|---|---|
derivative() | RationalFunction<T> | 商の微分: $\dfrac{d}{dx}\dfrac{P}{Q} = \dfrac{P'Q - PQ'}{Q^2}$ |
reciprocal() | RationalFunction<T> | 逆数 $Q(x)/P(x)$ |
pow(int n) | RationalFunction<T> | 整数冪 $(P/Q)^n$。$n < 0$ なら逆数の $|n|$ 乗 |
RationalFunction<double> f({1}, {1, 1}); // 1/(1+x)
std::cout << f.derivative().toString(); // 実行結果: -1/(x^2+2x+1) (= -1/(1+x)^2)
std::cout << f.reciprocal().toString(); // 実行結果: x+1
std::cout << f.pow(2).toString(); // 実行結果: 1/(x^2+2x+1)
部分分数分解
分母が単純根 (重根なし) のとき、Heaviside 法で $f(x) = \text{quotient}(x) + \sum_k \dfrac{A_k}{x - r_k}$ に分解する。 留数は $A_k = P(r_k)/Q'(r_k)$。
結果型:
template<typename T>
struct PartialFraction {
Complex<T> coefficient; // 留数 A_k
Complex<T> pole; // 極 r_k
};
template<typename T>
struct PartialFractionExpansion {
Polynomial<T> quotient; // deg(P) >= deg(Q) のときの多項式部
std::vector<PartialFraction<T>> terms; // 各部分分数項
bool success; // 分解に成功したか
};
| 関数 | 戻り値 | 説明 |
|---|---|---|
partialFractions(f, eps, maxIter) | PartialFractionExpansion<T> | Heaviside 分解 (単純根のみ)。重根検出時は success = false |
poles(f, eps, maxIter) | std::vector<Complex<T>> | 極 (分母 $Q$ の根) |
zeros(f, eps, maxIter) | std::vector<Complex<T>> | 零点 (分子 $P$ の根) |
residue(f, pole) | Complex<T> | 単純極での留数 $P(\text{pole})/Q'(\text{pole})$ |
パラメータ:
| 引数 | 型 | 説明 |
|---|---|---|
f | const RationalFunction<T>& | 分解する有理式 ($T$ は浮動小数型) |
eps | T | 重根判定・根の許容誤差 (既定 $\approx 100\,\varepsilon$) |
maxIter | size_t | 根の反復上限 (既定 1000) |
// 1 / (x^2 - 1) = 1/((x-1)(x+1)) 昇べき: {1} / {-1,0,1}
RationalFunction<double> f({1}, {-1, 0, 1});
auto pfe = partialFractions(f);
std::cout << pfe.success; // 実行結果: true
std::cout << pfe.terms.size(); // 実行結果: 2
std::cout << toString(pfe); // 実行結果: (0.5)/(x - (1)) + (-0.5)/(x - (-1))
auto ps = poles(f); // 極 {1, -1}
// ps[0].re = 1, ps[1].re = -1
極零相殺 (最小実現)
伝達関数を扱う際、分子・分母にほぼ等しい極零対が現れると数値的に不要な次数増加となる。
minimalRealization は近似 GCD でこれを相殺し、最小実現を返す (IIR フィルタの極零相殺など)。
| 関数 | 説明 |
|---|---|
minimalRealization(tf, tol = 1e-10) | 有理式から極零相殺して最小実現を返す |
minimalRealization(num, den, tol = 1e-10) | 分子・分母多項式から直接最小実現 |
chopSmallValues(f, eps) | 微小係数を 0 にして約分した有理式を返す (自由関数版) |
使用例
#include <math/core/RationalFunction.hpp>
#include <math/core/RationalFunction_partialFractions.hpp>
#include <iostream>
using namespace sangi;
int main() {
// (x^2 - 1)/(x - 1) は (x+1) に自動約分される
RationalFunction<double> f({-1, 0, 1}, {-1, 1});
std::cout << "f = " << f.toString() << "\n"; // f = x+1
// 四則: 1/(1+x) + x/(1+x) = 1
RationalFunction<double> a({1}, {1, 1}), b({0, 1}, {1, 1});
std::cout << "a+b = " << (a + b).toString() << "\n"; // a+b = 1
// 微分: d/dx 1/(1+x) = -1/(1+x)^2
std::cout << "da = " << a.derivative().toString() << "\n"; // da = -1/(x^2+2x+1)
// 部分分数: 1/(x^2-1) = 0.5/(x-1) - 0.5/(x+1)
RationalFunction<double> r({1}, {-1, 0, 1});
auto pfe = partialFractions(r);
if (pfe.success) std::cout << toString(pfe) << "\n";
// (0.5)/(x - (1)) + (-0.5)/(x - (-1))
}
関連モジュール
有理式は多項式の上に構築され、根の計算に求根モジュールを用いる。
- Polynomial — 多項式 — 分子・分母の表現と多項式演算
- Root Finding — 求根 — 極・零の計算に用いる多項式求根
- Complex — 複素数 — 極・零・留数の値型