LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
rational_polynomial.cpp
浏览该文件的文档.
2#include <algorithm>
3#include <optional>
4
5namespace LMCAS {
6
7static std::vector<BigInt> positive_divisors(const BigInt& n) {
8 std::vector<BigInt> divs;
9 if (n.is_zero()) {
10
11 return divs;
12 }
13 BigInt abs_n = n.abs();
14
15 BigInt i(1);
16
17 while (i * i <= abs_n) {
18 BigInt rem = abs_n % i;
19 if (rem.is_zero()) {
20 divs.push_back(i);
21 BigInt counterpart = abs_n / i;
22 if (counterpart != i) {
23 divs.push_back(counterpart);
24 }
25 }
26 i = i + BigInt(1);
27 }
28
29 std::sort(divs.begin(), divs.end());
30 return divs;
31}
32
33static std::optional<Rational> rational_root_candidate(
34 const Polynomial<Rational>& current) {
35 BigInt denominator_lcm(1);
36 for (const auto& coefficient : current.coeffs) {
37 denominator_lcm = BigInt::lcm(
38 denominator_lcm, coefficient.get_denominator());
39 }
40 const Rational scale(denominator_lcm);
41 const auto numerators = positive_divisors(
42 (current.coeffs[0] * scale).get_numerator());
43 const auto denominators = positive_divisors(
44 (current.lead_coeff() * scale).get_numerator());
45 for (const auto& numerator : numerators) {
46 for (const auto& denominator : denominators) {
47 Rational positive(numerator, denominator);
48 if (current.eval(positive) == Rational(0)) return positive;
49 Rational negative(-numerator, denominator);
50 if (current.eval(negative) == Rational(0)) return negative;
51 }
52 }
53 return std::nullopt;
54}
55
57 const Rational& root,
58 std::vector<Rational>& roots) {
59 Polynomial<Rational> linear({-root, Rational(1)}, current.variable_name);
60 while (current.degree() >= 1) {
61 auto [quotient, remainder] = current.div_mod(linear);
62 if (!remainder.is_zero()) break;
63 roots.push_back(root);
64 current = std::move(quotient);
65 if (current.degree() < 1 || current.eval(root) != Rational(0)) break;
66 }
67}
68
69std::vector<Rational> find_rational_roots(const Polynomial<Rational>& poly) {
70 std::vector<Rational> roots;
71 if (poly.is_zero() || poly.degree() < 1) return roots;
72 Polynomial<Rational> current = poly.make_monic();
73 while (current.degree() >= 1) {
74 if (current.coeffs[0] == Rational(0)) {
75 roots.push_back(Rational(0));
76 std::vector<Rational> coefficients(
77 current.coeffs.begin() + 1, current.coeffs.end());
78 current = Polynomial<Rational>(coefficients, current.variable_name);
79 continue;
80 }
81 if (current.degree() == 1) {
82 roots.push_back(-current.coeffs[0] / current.lead_coeff());
83 break;
84 }
85 auto candidate = rational_root_candidate(current);
86 if (!candidate) break;
87 deflate_rational_root(current, *candidate, roots);
88 }
89 return roots;
90}
91
92}
一元多项式模板类
CoeffType eval(const CoeffType &val) const
对多项式求值(Horner 法)
std::pair< Polynomial, Polynomial > div_mod(const Polynomial &other) const
多项式带余除法
std::string variable_name
变量名
bool is_zero() const
判断是否为零多项式
std::vector< CoeffType > coeffs
系数数组,coeffs[i] 为 x^i 的系数
CoeffType lead_coeff() const
获取首项系数
int degree() const
获取多项式的次数
Polynomial make_monic() const
首一化(使首项系数为 1)
static void deflate_rational_root(Polynomial< Rational > &current, const Rational &root, std::vector< Rational > &roots)
static std::optional< Rational > rational_root_candidate(const Polynomial< Rational > &current)
static std::vector< BigInt > positive_divisors(const BigInt &n)
std::vector< Rational > find_rational_roots(const Polynomial< Rational > &poly)
ExprSetResult roots(const ExprPtr &expression, const std::string &variable, ComputationContext &context, const SolveOptions &options)
const ExprPtr & denominator