8bool Rational::power_leq(BigInt base,
unsigned long exponent,
14 if (result > limit)
return false;
19 if (base > limit) base = limit + BigInt(1);
22 return result <= limit;
25BigInt Rational::integer_nth_root(
const BigInt&
value,
unsigned long degree) {
27 throw std::domain_error(
"Zeroth root is undefined");
29 if (
value < BigInt(0)) {
30 throw std::domain_error(
"Root input must be non-negative");
32 if (
value <= BigInt(1) || degree == 1) {
38 while (power_leq(high, degree,
value)) {
42 while (high - low > BigInt(1)) {
43 BigInt mid = (low + high) / BigInt(2);
44 if (power_leq(mid, degree,
value)) {
47 high = std::move(mid);
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)) {
60 if (n >
static_cast<std::int64_t
>(max_decimal_scale / 2)) {
61 throw std::length_error(
"Square-root precision exceeds safety limit");
64 BigInt numerator_root = numerator.sqrt();
66 if (numerator_root * numerator_root == numerator &&
67 denominator_root * denominator_root ==
denominator) {
68 numerator = std::move(numerator_root);
74 const BigInt scale = pow10(
static_cast<std::size_t
>(n));
75 const BigInt scaled = numerator * scale * scale /
denominator;
76 numerator = scaled.sqrt();
81Rational Rational::sqrt(std::int64_t n)
const{
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");
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");
97 if (n >
static_cast<std::int64_t
>(max_decimal_scale / degree)) {
98 throw std::length_error(
"Root precision exceeds safety limit");
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;
109Rational Rational::radicand(
const BigInt& radical, std::int64_t n) {
111 re.radicand_self(radical, n);
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");
120 result.radicand_self(
exponent.denominator,
static_cast<std::int64_t
>(n));
121 *
this = std::move(result);
@ Rational
Rational numbers
ExprResult simplify(const ExprPtr &expression, ComputationContext &context)
const std::string const ExprPtr & value
const ExprPtr & denominator
精确有理数 Rational,基于 BigInt 分子/分母表示,自动约分。