LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
irrational_arithmetic.cpp
浏览该文件的文档.
1#include "irrational.hpp"
3#include <limits>
4#include <new>
5#include <optional>
6#include <stdexcept>
7
8namespace LMCAS {
9
10void Irrational::add_term(Terms& terms, const Basis& basis, const Rational& coefficient) {
11 if (coefficient.is_zero()) return;
12 auto inserted = terms.emplace(basis, coefficient);
13 if (inserted.second) return;
14 auto& value = inserted.first->second;
15 value = value + coefficient;
16 if (value.is_zero()) terms.erase(inserted.first);
17}
18
19Irrational::Terms Irrational::multiply_terms(const Terms& left, const Terms& right) {
20 Terms result;
21 for (const auto& a : left) {
22 for (const auto& b : right) {
23 const BigInt common = BigInt::gcd(a.first.radicand, b.first.radicand);
24 Basis basis;
25 basis.radicand = (a.first.radicand / common) * (b.first.radicand / common);
26 basis.pi_power = a.first.pi_power + b.first.pi_power;
27 basis.e_power = a.first.e_power + b.first.e_power;
28 add_term(result, basis, a.second * b.second * Rational(common));
29 }
30 }
31 return result;
32}
33
34Irrational Irrational::operator+(const Irrational& other) const {
35 Irrational result;
36 if (denominator_ == other.denominator_) {
37 result.numerator_ = numerator_;
38 result.denominator_ = denominator_;
39 for (const auto& term : other.numerator_) {
40 add_term(result.numerator_, term.first, term.second);
41 }
42 } else {
43 result.numerator_ = multiply_terms(numerator_, other.denominator_);
44 const Terms right = multiply_terms(other.numerator_, denominator_);
45 for (const auto& term : right) add_term(result.numerator_, term.first, term.second);
46 result.denominator_ = multiply_terms(denominator_, other.denominator_);
47 }
48 result.simplify();
49 return result;
50}
51
52Irrational Irrational::operator-(const Irrational& other) const {
53 return *this + (-other);
54}
55
56Irrational Irrational::operator*(const Irrational& other) const {
57 Irrational result;
58 result.numerator_ = multiply_terms(numerator_, other.numerator_);
59 result.denominator_ = multiply_terms(denominator_, other.denominator_);
60 result.simplify();
61 return result;
62}
63
64Irrational Irrational::operator*(const Rational& scalar) const {
65 Irrational result = *this;
66 if (scalar.is_zero()) {
67 result.numerator_.clear();
68 } else {
69 for (auto& term : result.numerator_) term.second = term.second * scalar;
70 }
71 return result;
72}
73
74Irrational Irrational::operator*(lmmc_real_t scalar) const {
75 return *this * Rational::from_double(scalar);
76}
77
78Irrational Irrational::operator/(const Irrational& other) const {
79 if (other.is_zero()) throw std::domain_error("Irrational: division by zero");
80 Irrational result;
81 result.numerator_ = multiply_terms(numerator_, other.denominator_);
82 result.denominator_ = multiply_terms(denominator_, other.numerator_);
83 result.simplify();
84 return result;
85}
86
87Irrational Irrational::operator-() const {
88 return *this * Rational(-1);
89}
90
91Irrational Irrational::pow(const BigInt& exponent) const {
92 BigInt remaining = exponent.abs();
93 Irrational result = constant(Rational(1));
94 Irrational base = *this;
95 while (!remaining.is_zero()) {
96 if (remaining.is_odd()) result = result * base;
97 remaining >>= 1;
98 if (!remaining.is_zero()) base = base * base;
99 }
100 return exponent.is_negative() ? constant(Rational(1)) / result : result;
101}
102
103bool Irrational::operator==(const Irrational& other) const {
104 if (denominator_ == other.denominator_) return numerator_ == other.numerator_;
105 return multiply_terms(numerator_, other.denominator_) ==
106 multiply_terms(other.numerator_, denominator_);
107}
108
109bool Irrational::operator<(const Irrational& other) const {
110 auto left = as_rational_checked();
111 auto right = other.as_rational_checked();
112 if (left && right) return left.value() < right.value();
113 if (*this == other) return false;
114 return to_double() < other.to_double();
115}
116
117bool Irrational::operator<=(const Irrational& other) const {
118 return *this < other || *this == other;
119}
120
121bool Irrational::operator>(const Irrational& other) const {
122 return other < *this;
123}
124
125bool Irrational::operator>=(const Irrational& other) const {
126 return other <= *this;
127}
128
129bool Irrational::is_positive() const {
130 return constant(Rational(0)) < *this;
131}
132
133bool Irrational::is_negative() const {
134 return *this < constant(Rational(0));
135}
136
140 std::size_t precision;
142 std::map<BigInt, Bounds> radicals;
143 std::optional<Bounds> pi;
144 std::optional<Bounds> e;
145
148 arithmetic(context, "Irrational::sign_checked") {}
149
150 const Bounds& radical(const BigInt& radicand) {
151 auto found = radicals.find(radicand);
152 if (found != radicals.end()) return found->second;
154 if (radicand.is_negative() || radicand.is_zero())
156 "nonpositive normalized radicand", "Irrational::sign_checked"};
157 if (radicand == BigInt(1))
158 return radicals.emplace(radicand, Bounds{Rational(1), Rational(1)}).first->second;
159 const BigInt scale = arithmetic.dyadic_scale(precision);
160 const auto shift = arithmetic.growth(precision, precision);
161 arithmetic.growth(radicand.bit_length(), shift);
162 if (shift > std::numeric_limits<mp_size_t>::max())
164 "radical shift size exceeded", "Irrational::sign_checked"};
165 const BigInt scaled = radicand << static_cast<mp_size_t>(shift);
167 const BigInt lower = scaled.sqrt();
168 arithmetic.growth(lower.bit_length(), lower.bit_length());
169 const bool exact = lower * lower == scaled;
170 arithmetic.growth(lower.bit_length(), 1);
171 const BigInt upper = exact ? lower : lower + BigInt(1);
172 return radicals.emplace(radicand, Bounds{Rational(lower, scale),
173 Rational(upper, scale)}).first->second;
174 }
175
176 const Bounds& constant(bool use_pi) {
177 auto& cached = use_pi ? pi : e;
178 if (!cached) {
179 auto bounds = use_pi ? detail::exact_pi_bounds(precision, context)
181 if (!bounds) throw bounds.error();
182 cached = std::move(bounds.value());
183 }
184 return *cached;
185 }
186
188 return {arithmetic.mul(a.first, b.first), arithmetic.mul(a.second, b.second)};
189 }
190
191 Bounds power(Bounds base, const BigInt& exponent) {
192 arithmetic.bits(exponent.bit_length());
193 BigInt remaining = exponent.abs();
194 Bounds result{Rational(1), Rational(1)};
195 while (!remaining.is_zero()) {
197 if (remaining.is_odd()) result = multiply_positive(result, base);
198 remaining >>= 1;
199 if (!remaining.is_zero()) base = multiply_positive(base, base);
200 }
201 if (exponent.is_negative())
202 return {arithmetic.div(Rational(1), result.second),
203 arithmetic.div(Rational(1), result.first)};
204 return result;
205 }
206
207 static bool validate_terms(const Terms& terms,
208 detail::ExactBoundArithmetic& arithmetic, bool& transcendental) {
209 bool zero = true;
210 for (const auto& term : terms) {
212 arithmetic.bits(term.second.get_numerator().bit_length());
213 arithmetic.bits(term.second.get_denominator().bit_length());
214 arithmetic.bits(term.first.radicand.bit_length());
215 arithmetic.bits(term.first.pi_power.bit_length());
216 arithmetic.bits(term.first.e_power.bit_length());
217 if (term.second.is_zero()) { continue; }
218 zero = false;
219 transcendental |= !term.first.pi_power.is_zero() ||
220 !term.first.e_power.is_zero();
221 }
222 return zero;
223 }
224
225 static int separated_sign(const Bounds& bounds) {
226 const auto lower = bounds.first.get_numerator();
227 if (!lower.is_zero() && !lower.is_negative()) { return 1; }
228 if (bounds.second.get_numerator().is_negative()) { return -1; }
229 return 0;
230 }
231
232 static Result<Sign> refine_sign(const Terms& numerator, const Terms& denominator,
233 bool numerator_zero, bool transcendental, ComputationContext& context,
234 detail::ExactBoundArithmetic& arithmetic, const char* operation) {
235 /**
236 * @brief 不同规范无平方因子根式在 Q 上线性无关,故非空纯根式和非零,细化过程在数学上终止;
237 * 实际执行仍受调用方资源预算限制。
238 */
239 for (std::size_t precision = 32;;) {
242 const auto denominator_bounds = terms_bounds(denominator, round);
243 const int denominator_sign = separated_sign(denominator_bounds);
244 if (denominator_sign != 0) {
245 if (numerator_zero) { return Sign::Zero; }
246 const auto numerator_bounds = terms_bounds(numerator, round);
247 const int numerator_sign = separated_sign(numerator_bounds);
248 if (numerator_sign != 0) {
249 return numerator_sign == denominator_sign ? Sign::Positive : Sign::Negative;
250 }
251 }
252 if (transcendental && precision == 4096) {
254 "pi/e enclosure did not separate zero at 4096 bits", operation);
255 }
256 if (precision > std::numeric_limits<std::size_t>::max() / 2) {
258 "refinement size exceeded", operation);
259 }
260 precision *= 2;
261 }
262 }
263};
264
265std::pair<Rational, Rational> Irrational::terms_bounds(
266 const Terms& terms, EnclosureRound& round) {
267 auto& arithmetic = round.arithmetic;
268 EnclosureRound::Bounds sum{Rational(0), Rational(0)};
269 for (const auto& term : terms) {
270 arithmetic.step();
271 if (term.second.is_zero()) continue;
272 auto basis = round.radical(term.first.radicand);
273 if (!term.first.pi_power.is_zero())
274 basis = round.multiply_positive(
275 basis, round.power(round.constant(true), term.first.pi_power));
276 if (!term.first.e_power.is_zero())
277 basis = round.multiply_positive(
278 basis, round.power(round.constant(false), term.first.e_power));
279 if (term.second.get_numerator().is_negative()) std::swap(basis.first, basis.second);
280 sum.first = arithmetic.add(sum.first, arithmetic.mul(term.second, basis.first));
281 sum.second = arithmetic.add(sum.second, arithmetic.mul(term.second, basis.second));
282 }
283 return sum;
284}
285
286Result<Sign> Irrational::sign_checked(ComputationContext& context) const {
287 const char* operation = "Irrational::sign_checked";
288 try {
289 detail::ExactBoundArithmetic arithmetic(context, operation);
290 arithmetic.step();
291 arithmetic.require(context.require_expansion_terms(numerator_.size(), operation));
292 arithmetic.require(context.require_expansion_terms(denominator_.size(), operation));
293 bool transcendental = false;
294 const bool numerator_zero = EnclosureRound::validate_terms(
295 numerator_, arithmetic, transcendental);
296 const bool denominator_zero = EnclosureRound::validate_terms(
297 denominator_, arithmetic, transcendental);
298 if (denominator_zero) {
299 return Result<Sign>::failure(CasErrc::DomainError, "zero denominator", operation);
300 }
301 return EnclosureRound::refine_sign(numerator_, denominator_, numerator_zero,
302 transcendental, context, arithmetic, operation);
303 } catch (const CasError& error) {
304 return Result<Sign>::failure(error);
305 } catch (const std::bad_alloc&) {
306 return Result<Sign>::failure(CasErrc::ResourceLimit, "sign enclosure allocation failed", operation);
307 } catch (const std::length_error&) {
308 return Result<Sign>::failure(CasErrc::ResourceLimit, "sign enclosure size exceeded", operation);
309 }
310}
311
312Result<Sign> Irrational::sign_checked() const {
314 return sign_checked(context);
315}
316
317Result<Irrational> Irrational::abs_checked(ComputationContext& context) const {
318 auto sign = sign_checked(context);
319 if (!sign) return Result<Irrational>::failure(sign.error());
320 try {
321 if (sign.value() == Sign::Zero) return constant(Rational(0));
322 Irrational result = *this;
323 if (sign.value() == Sign::Negative) {
324 for (auto& term : result.numerator_) {
325 auto step = context.consume_steps(1, "Irrational::abs_checked");
326 if (!step) return Result<Irrational>::failure(step.error());
327 term.second = -term.second; /**< 取负保持分子、分母整数的位数不变。 */
328 }
329 }
330 return result;
331 } catch (const std::bad_alloc&) {
333 "absolute value allocation failed", "Irrational::abs_checked");
334 } catch (const std::length_error&) {
336 "absolute value size exceeded", "Irrational::abs_checked");
337 }
338}
339
340Result<Irrational> Irrational::abs_checked() const {
342 return abs_checked(context);
343}
344
345Irrational Irrational::abs() const {
346 auto result = abs_checked();
347 if (result) return std::move(result.value());
348 const auto& error = result.error();
349 const std::string message = error.operation + ": " + error.message;
350 switch (error.code) {
351 case CasErrc::DomainError: throw std::domain_error(message);
352 case CasErrc::ResourceLimit: throw std::length_error(message);
353 case CasErrc::InternalInvariant: throw std::logic_error(message);
354 default: throw std::runtime_error(message);
355 }
356}
357
358}
static Result failure(CasErrc code, std::string message, std::string operation={})
常数及根式包围区间共用的内部算术策略。 保守界覆盖未约分 Rational 的交叉乘积及结果;受检入口统一捕获 CasError,仅返回完整结果。
Rational mul(const Rational &a, const Rational &b) const
std::size_t growth(std::size_t a, std::size_t b) const
Rational div(const Rational &a, const Rational &b) const
BigInt dyadic_scale(std::size_t precision) const
精确实根式及根式、pi、e 的有理组合。
Result< ExactConstantInterval > exact_e_bounds(std::size_t precision_bits, ComputationContext &context)
std::pair< Rational, Rational > ExactConstantInterval
ComputationContext const std::string & operation
Result< ExactConstantInterval > exact_pi_bounds(std::size_t precision_bits, ComputationContext &context)
__attribute__((visibility("default"))) ExprResult function(const std __attribute__((visibility("default"))) ExprResult finite_set(std ExprPtr upper
const std::vector< Polynomial< BigInt > > const BigInt ComputationContext & context
const ExprPtr & lower
@ Rational
Rational numbers
const MultiPoly & b
const ExprPtr & exponent
__attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) VectorCalculusExprResult curve_integral_scalar_checked(const std __attribute__((visibility("default"))) std const VectorField const std::string const std::shared_ptr< SymbolicExpr > & a
const ExprPtr & right
const std::vector< FGLMPoly > & basis
const std::string const ExprPtr & value
const ExprPtr & denominator
ExprResult round(const ExprPtr &expression, ComputationContext &context)
Bounds multiply_positive(const Bounds &a, const Bounds &b)
static Result< Sign > refine_sign(const Terms &numerator, const Terms &denominator, bool numerator_zero, bool transcendental, ComputationContext &context, detail::ExactBoundArithmetic &arithmetic, const char *operation)
static int separated_sign(const Bounds &bounds)
const Bounds & radical(const BigInt &radicand)
static bool validate_terms(const Terms &terms, detail::ExactBoundArithmetic &arithmetic, bool &transcendental)
EnclosureRound(ComputationContext &context, std::size_t precision)
Bounds power(Bounds base, const BigInt &exponent)