LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
irrational.cpp
浏览该文件的文档.
1#include "irrational.hpp"
2#include <cmath>
3#include <new>
4#include <utility>
5
6namespace LMCAS {
7
8bool Irrational::Basis::operator<(const Basis& other) const {
9 if (radicand != other.radicand) return radicand < other.radicand;
10 if (pi_power != other.pi_power) return pi_power < other.pi_power;
11 return e_power < other.e_power;
12}
13
14bool Irrational::Basis::operator==(const Basis& other) const {
15 return radicand == other.radicand && pi_power == other.pi_power &&
16 e_power == other.e_power;
17}
18
19bool Irrational::Basis::is_constant() const {
20 return radicand == BigInt(1) && pi_power.is_zero() && e_power.is_zero();
21}
22
23Result<std::pair<BigInt, BigInt>> Irrational::extract_square_factors(
24 const BigInt& n, ComputationContext& context) {
25 using Factors = std::pair<BigInt, BigInt>;
26 if (n.is_zero()) return Factors{BigInt(0), BigInt(1)};
27 const BigInt root = n.sqrt();
28 if (root * root == n) return Factors{root, BigInt(1)};
29 BigInt perfect(1);
30 BigInt remainder = n;
31 const BigInt one(1);
32 for (BigInt divisor(2); divisor <= remainder / divisor; divisor += one) {
33 auto step = context.consume_steps(1, "Irrational::sqrt_checked");
34 if (!step) return Result<Factors>::failure(step.error());
35 const BigInt square = divisor * divisor;
36 while ((remainder % square).is_zero()) {
37 step = context.consume_steps(1, "Irrational::sqrt_checked");
38 if (!step) return Result<Factors>::failure(step.error());
39 perfect *= divisor;
40 remainder /= square;
41 }
42 }
43 return Factors{std::move(perfect), std::move(remainder)};
44}
45
46Result<Irrational> Irrational::sqrt_checked(const BigInt& n, lmmc_real_t coefficient,
48 const std::string operation = "Irrational::sqrt_checked";
49 auto step = context.consume_steps(1, operation);
50 if (!step) {
51 return Result<Irrational>::failure(step.error());
52 }
53 if (n.is_negative()) {
55 "negative square root radicand", operation);
56 }
57 if (!std::isfinite(coefficient)) {
59 "square root coefficient must be finite", operation);
60 }
61 auto bits = context.require_integer_bits(n.bit_length(), operation);
62 if (!bits) {
63 return Result<Irrational>::failure(bits.error());
64 }
65 try {
66 Rational exact = Rational::from_double(coefficient);
67 bits = context.require_integer_bits(exact.get_numerator().bit_length(), operation);
68 if (!bits) {
69 return Result<Irrational>::failure(bits.error());
70 }
71 bits = context.require_integer_bits(exact.get_denominator().bit_length(), operation);
72 if (!bits) {
73 return Result<Irrational>::failure(bits.error());
74 }
75 Irrational result;
76 result.type_ = Type::SQRT;
77 if (exact.is_zero() || n.is_zero()) {
78 return result;
79 }
80 auto factors = extract_square_factors(n, context);
81 if (!factors) {
82 return Result<Irrational>::failure(factors.error());
83 }
84 exact = exact * Rational(factors.value().first);
85 bits = context.require_integer_bits(exact.get_numerator().bit_length(), operation);
86 if (!bits) {
87 return Result<Irrational>::failure(bits.error());
88 }
89 Basis basis;
90 basis.radicand = std::move(factors.value().second);
91 result.numerator_.emplace(std::move(basis), std::move(exact));
92 return result;
93 } catch (const std::bad_alloc&) {
95 "square root allocation failed", operation);
96 }
97}
98
99Result<Irrational> Irrational::sqrt_checked(const BigInt& n, lmmc_real_t coefficient) {
101 return sqrt_checked(n, coefficient, context);
102}
103
104Irrational Irrational::pi(lmmc_real_t coefficient) {
105 Irrational result;
106 result.type_ = Type::PI;
107 Basis basis;
108 basis.pi_power = BigInt(1);
109 add_term(result.numerator_, basis, Rational::from_double(coefficient));
110 return result;
111}
112
113Irrational Irrational::e(lmmc_real_t coefficient) {
114 Irrational result;
115 result.type_ = Type::E;
116 Basis basis;
117 basis.e_power = BigInt(1);
118 add_term(result.numerator_, basis, Rational::from_double(coefficient));
119 return result;
120}
121
122Irrational Irrational::constant(lmmc_real_t value) {
123 return constant(Rational::from_double(value));
124}
125
126Irrational Irrational::constant(const Rational& value) {
127 Irrational result;
128 add_term(result.numerator_, Basis{}, value);
129 return result;
130}
131
132bool Irrational::is_zero() const {
133 return numerator_.empty();
134}
135
136Result<Rational> Irrational::as_rational_checked() const {
137 if (is_zero()) return Rational(0);
138 if (numerator_.size() == denominator_.size()) {
139 const Rational ratio = numerator_.begin()->second / denominator_.begin()->second;
140 auto numerator = numerator_.begin();
141 auto denominator = denominator_.begin();
142 for (; numerator != numerator_.end(); ++numerator, ++denominator) {
143 if (!(numerator->first == denominator->first) ||
144 numerator->second != denominator->second * ratio) break;
145 }
146 if (numerator == numerator_.end()) return ratio;
147 }
149 "irrational value is not rational",
150 "Irrational::as_rational_checked");
151}
152
153bool Irrational::is_rational() const {
154 return as_rational_checked().has_value();
155}
156
157void Irrational::simplify() {
158 /**
159 * @brief 纯根式非空和由 Q 线性无关性保证非零;规范单项式因各基值为正而非零。
160 * 含 pi/e 的多项式不采用该线性无关性结论;即使分子为零或与分母成比例,
161 * 也保留分母,由 sign_checked 证明其非零后再返回值。
162 */
163 if (denominator_.size() > 1) {
164 for (const auto& term : denominator_) {
165 if (!term.first.pi_power.is_zero() || !term.first.e_power.is_zero())
166 return;
167 }
168 }
169 auto rational = as_rational_checked();
170 if (rational) {
171 numerator_.clear();
172 denominator_.clear();
173 denominator_.emplace(Basis{}, Rational(1));
174 add_term(numerator_, Basis{}, rational.value());
175 } else if (denominator_.size() == 1 && denominator_.begin()->first.is_constant()) {
176 const Rational divisor = denominator_.begin()->second;
177 for (auto& term : numerator_) term.second = term.second / divisor;
178 denominator_.begin()->second = Rational(1);
179 }
180}
181
182}
static Result failure(CasErrc code, std::string message, std::string operation={})
精确实根式及根式、pi、e 的有理组合。
bool is_zero(const SymbolicExpr &expression)
ComputationContext const std::string & operation
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
@ Rational
Rational numbers
const std::vector< FGLMPoly > & basis
const std::string const ExprPtr & value
const ExprPtr & denominator
ExprResult rational(const Rational &value)