LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
rational_roots.cpp
浏览该文件的文档.
1#include "rational.hpp"
2#include <limits>
3#include <stdexcept>
4#include <utility>
5
6namespace LMCAS {
7
8bool Rational::power_leq(BigInt base, unsigned long exponent,
9 const BigInt& limit) {
10 BigInt result(1);
11 while (exponent != 0) {
12 if ((exponent & 1UL) != 0) {
13 result *= base;
14 if (result > limit) return false;
15 }
16 exponent >>= 1UL;
17 if (exponent != 0) {
18 base *= base;
19 if (base > limit) base = limit + BigInt(1);
20 }
21 }
22 return result <= limit;
23}
24
25BigInt Rational::integer_nth_root(const BigInt& value, unsigned long degree) {
26 if (degree == 0) {
27 throw std::domain_error("Zeroth root is undefined");
28 }
29 if (value < BigInt(0)) {
30 throw std::domain_error("Root input must be non-negative");
31 }
32 if (value <= BigInt(1) || degree == 1) {
33 return value;
34 }
35
36 BigInt low(0);
37 BigInt high(1);
38 while (power_leq(high, degree, value)) {
39 high *= BigInt(2);
40 }
41
42 while (high - low > BigInt(1)) {
43 BigInt mid = (low + high) / BigInt(2);
44 if (power_leq(mid, degree, value)) {
45 low = std::move(mid);
46 } else {
47 high = std::move(mid);
48 }
49 }
50 return low;
51}
52
53void Rational::sqrt_self(std::int64_t n) {
54 if (n < 0) throw std::invalid_argument("Square-root precision must be non-negative");
55 if (numerator < BigInt(0)) throw std::domain_error("Square root of a negative Rational");
56 if (numerator == BigInt(0)) {
57 denominator = BigInt(1);
58 return;
59 }
60 if (n > static_cast<std::int64_t>(max_decimal_scale / 2)) {
61 throw std::length_error("Square-root precision exceeds safety limit");
62 }
63
64 BigInt numerator_root = numerator.sqrt();
65 BigInt denominator_root = denominator.sqrt();
66 if (numerator_root * numerator_root == numerator &&
67 denominator_root * denominator_root == denominator) {
68 numerator = std::move(numerator_root);
69 denominator = std::move(denominator_root);
70 simplify();
71 return;
72 }
73
74 const BigInt scale = pow10(static_cast<std::size_t>(n));
75 const BigInt scaled = numerator * scale * scale / denominator;
76 numerator = scaled.sqrt();
77 denominator = scale;
78 simplify();
79}
80
81Rational Rational::sqrt(std::int64_t n) const{
82 Rational re = *this;
83 re.sqrt_self(n);
84 return re;
85}
86
87void Rational::radicand_self(const BigInt& radical, std::int64_t n) {
88 if (radical <= BigInt(0)) throw std::domain_error("Root degree must be positive");
89 if (radical > BigInt(1024)) throw std::length_error("Root degree exceeds safety limit");
90 if (n < 0) throw std::invalid_argument("Root precision must be non-negative");
91
92 const unsigned long degree = static_cast<unsigned long>(*radical.try_to_uint64());
93 const bool negative = numerator < BigInt(0);
94 if (negative && (degree % 2UL) == 0) {
95 throw std::domain_error("Even root of a negative Rational");
96 }
97 if (n > static_cast<std::int64_t>(max_decimal_scale / degree)) {
98 throw std::length_error("Root precision exceeds safety limit");
99 }
100
101 const BigInt scale = pow10(static_cast<std::size_t>(n));
102 const BigInt scaled = numerator.abs() * scale.power(degree) / denominator;
103 numerator = integer_nth_root(scaled, degree);
104 if (negative) numerator = -numerator;
105 denominator = scale;
106 simplify();
107}
108
109Rational Rational::radicand(const BigInt& radical, std::int64_t n) {
110 Rational re = *this;
111 re.radicand_self(radical, n);
112 return re;
113}
114
115void Rational::power_self(const Rational& exponent, std::size_t n) {
116 Rational result = power(exponent.numerator);
117 if (n > static_cast<std::uint64_t>(std::numeric_limits<std::int64_t>::max())) {
118 throw std::length_error("Root precision exceeds safety limit");
119 }
120 result.radicand_self(exponent.denominator, static_cast<std::int64_t>(n));
121 *this = std::move(result);
122}
123
124Rational Rational::power(const Rational& exponent, std::size_t n) {
125 Rational re = *this;
126 re.power_self(exponent, n);
127 return re;
128}
129
130}
@ Rational
Rational numbers
ExprResult simplify(const ExprPtr &expression, ComputationContext &context)
const ExprPtr & exponent
const std::string const ExprPtr & value
const ExprPtr & denominator
精确有理数 Rational,基于 BigInt 分子/分母表示,自动约分。