LMCAS
Lamina Computer Algebra System
Toggle main menu visibility
载入中...
搜索中...
未找到
numeric_evaluation_power.cpp
浏览该文件的文档.
1
#include "
internal/numeric_evaluation_support.hpp
"
2
#include <cmath>
3
#include <algorithm>
4
#include <limits>
5
6
namespace
LMCAS::detail
{
7
namespace
{
8
9
struct
ExponentParity
{
10
bool
integral
;
11
bool
odd
;
12
};
13
14
ExponentParity
exponent_parity
(
const
PowerNode
& power,
double
value
) {
15
const
auto
* number =
dynamic_cast<
const
NumberNode
*
>
(power.
exponent
().get());
16
const
auto
*
integer
= number ? std::get_if<BigInt>(&number->value()) :
nullptr
;
17
if
(
integer
) {
18
return
{
true
,
integer
->is_odd()};
19
}
20
const
auto
*
rational
= number ? std::get_if<Rational>(&number->value()) :
nullptr
;
21
if
(
rational
) {
22
const
bool
integral =
rational
->is_integer();
23
return
{integral, integral &&
rational
->get_numerator().is_odd()};
24
}
25
const
bool
integral = std::trunc(
value
) ==
value
;
26
return
{integral, integral && std::fmod(
value
, 2.0) != 0.0};
27
}
28
29
}
30
31
Result<ApproxReal>
NumericEvaluator::square_root
(
const
NumberNode
&
node
) {
32
auto
step =
context_
.
consume_steps
(1,
"evaluate_numeric"
);
33
if
(!step)
return
Result<ApproxReal>::failure
(step.error());
34
if
(
node
.is_zero())
return
numeric_approximation
(0.0);
35
BigInt numerator;
36
BigInt
denominator
(1);
37
if
(
const
auto
*
integer
= std::get_if<BigInt>(&
node
.value())) {
38
numerator = *
integer
;
39
}
else
{
40
const
auto
&
rational
= std::get<Rational>(
node
.value());
41
numerator =
rational
.get_numerator();
42
denominator
=
rational
.get_denominator();
43
}
44
if
(numerator.is_negative()) {
45
return
numeric_failure
(
CasErrc::DomainError
,
46
"real square root requires a non-negative argument"
);
47
}
48
const
auto
num_bits = numerator.bit_length();
49
const
auto
den_bits =
denominator
.bit_length();
50
auto
bits =
context_
.
require_integer_bits
(std::max(num_bits, den_bits),
"evaluate_numeric"
);
51
if
(!bits)
return
Result<ApproxReal>::failure
(bits.error());
52
const
bool
reciprocal_scale = num_bits < den_bits;
53
const
auto
difference = reciprocal_scale ? den_bits - num_bits : num_bits - den_bits;
54
constexpr
int
max_scale = 2 * std::numeric_limits<double>::max_exponent;
55
constexpr
int
min_scale = 2 * (std::numeric_limits<double>::digits -
56
std::numeric_limits<double>::min_exponent + 1);
57
if
(difference >
static_cast<
std::size_t
>
(reciprocal_scale ? min_scale : max_scale)) {
58
return
numeric_failure
(
CasErrc::NumericFailure
,
"numeric square root is outside the floating-point range"
);
59
}
60
const
auto
shift = difference - difference % 2;
61
if
(reciprocal_scale) numerator <<= shift;
62
else
denominator
<<= shift;
63
const
int
scale =
static_cast<
int
>
(shift / 2) * (reciprocal_scale ? -1 : 1);
64
const
double
value
= std::ldexp(std::sqrt(Rational(numerator,
denominator
).to_double()), scale);
65
if
(
value
== 0.0) {
66
return
numeric_failure
(
CasErrc::NumericFailure
,
"numeric square root underflow"
);
67
}
68
return
numeric_approximation
(
value
);
69
}
70
71
Result<ApproxReal>
NumericEvaluator::power
(
const
PowerNode
&
node
) {
72
const
auto
* base_number =
dynamic_cast<
const
NumberNode
*
>
(
node
.base().get());
73
const
auto
* exponent_number =
dynamic_cast<
const
NumberNode
*
>
(
node
.exponent().get());
74
if
(base_number && exponent_number) {
75
const
auto
*
exponent
= std::get_if<Rational>(&exponent_number->value());
76
if
(
exponent
&& *
exponent
== Rational(1, 2)) {
77
auto
step =
context_
.
consume_steps
(1,
"evaluate_numeric"
);
78
if
(!step)
return
Result<ApproxReal>::failure
(step.error());
79
return
square_root
(*base_number);
80
}
81
if
(exponent_number->is_negative_one()) {
82
auto
step =
context_
.
consume_steps
(2,
"evaluate_numeric"
);
83
if
(!step)
return
Result<ApproxReal>::failure
(step.error());
84
if
(base_number->is_zero()) {
85
return
numeric_failure
(
CasErrc::DomainError
,
"zero cannot be raised to a non-positive power"
);
86
}
87
try
{
88
if
(
const
auto
*
integer
= std::get_if<BigInt>(&base_number->value())) {
89
return
numeric_approximation
(Rational(BigInt(1), *
integer
).to_double());
90
}
91
const
auto
&
rational
= std::get<Rational>(base_number->value());
92
return
numeric_approximation
(
93
Rational(
rational
.get_denominator(),
rational
.get_numerator()).to_double());
94
}
catch
(
const
std::range_error& error) {
95
return
numeric_failure
(
CasErrc::NumericFailure
, error.what());
96
}
catch
(
const
std::overflow_error& error) {
97
return
numeric_failure
(
CasErrc::NumericFailure
, error.what());
98
}
catch
(
const
std::underflow_error& error) {
99
return
numeric_failure
(
CasErrc::NumericFailure
, error.what());
100
}
101
}
102
}
103
auto
base =
evaluate
(
node
.base());
104
if
(!base) {
105
return
base;
106
}
107
auto
exponent
=
evaluate
(
node
.exponent());
108
if
(!
exponent
) {
109
return
exponent
;
110
}
111
const
double
base_value = base.value().value;
112
const
double
exponent_value =
exponent
.value().value;
113
if
(base_value == 0.0 && exponent_value <= 0.0) {
114
return
numeric_failure
(
CasErrc::DomainError
,
"zero cannot be raised to a non-positive power"
);
115
}
116
if
(std::signbit(base_value) && std::isfinite(exponent_value)) {
117
const
auto
parity = exponent_parity(
node
, exponent_value);
118
if
(base_value < 0.0 && std::isfinite(base_value) && !parity.integral) {
119
return
numeric_failure
(
CasErrc::DomainError
,
120
"a negative real base requires an integer exponent"
);
121
}
122
if
(parity.integral) {
123
const
double
magnitude = std::pow(std::abs(base_value), exponent_value);
124
if
(magnitude == 0.0 && base_value != 0.0) {
125
return
numeric_failure
(
CasErrc::NumericFailure
,
"numeric power underflow"
);
126
}
127
return
numeric_approximation
(parity.odd ? -magnitude : magnitude);
128
}
129
}
130
const
double
value
= std::pow(base_value, exponent_value);
131
if
(
value
== 0.0 && base_value != 0.0) {
132
return
numeric_failure
(
CasErrc::NumericFailure
,
"numeric power underflow"
);
133
}
134
return
numeric_approximation
(
value
);
135
}
136
137
}
LMCAS::ComputationContext::consume_steps
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
定义
computation_context.hpp:112
LMCAS::ComputationContext::require_integer_bits
Result< void > require_integer_bits(std::size_t amount, const std::string &operation={}) const
定义
computation_context.hpp:151
LMCAS::NumberNode
定义
numbers.hpp:8
LMCAS::PowerNode
幂运算节点,表示 base^exponent。
定义
arithmetic.hpp:218
LMCAS::PowerNode::exponent
const std::shared_ptr< const SymbolicNode > & exponent() const noexcept
定义
arithmetic.hpp:234
LMCAS::Result
定义
result.hpp:39
LMCAS::Result::failure
static Result failure(CasErrc code, std::string message, std::string operation={})
定义
result.hpp:52
LMCAS::detail::NumericEvaluator::square_root
Result< ApproxReal > square_root(const NumberNode &node)
定义
numeric_evaluation_power.cpp:31
LMCAS::detail::NumericEvaluator::evaluate
Result< ApproxReal > evaluate(const std::shared_ptr< const SymbolicNode > &node)
定义
numeric_evaluation.cpp:36
LMCAS::detail::NumericEvaluator::context_
ComputationContext & context_
定义
numeric_evaluation_support.hpp:22
LMCAS::detail::NumericEvaluator::power
Result< ApproxReal > power(const PowerNode &node)
定义
numeric_evaluation_power.cpp:71
LMCAS::detail::anonymous_namespace{numeric_evaluation_power.cpp}::ExponentParity::integral
bool integral
定义
numeric_evaluation_power.cpp:10
LMCAS::detail::anonymous_namespace{numeric_evaluation_power.cpp}::exponent_parity
ExponentParity exponent_parity(const PowerNode &power, double value)
定义
numeric_evaluation_power.cpp:14
LMCAS::detail::anonymous_namespace{numeric_evaluation_power.cpp}::ExponentParity::odd
bool odd
定义
numeric_evaluation_power.cpp:11
LMCAS::detail::anonymous_namespace{numeric_evaluation_power.cpp}::ExponentParity
定义
numeric_evaluation_power.cpp:9
LMCAS::detail
多元 Hensel 提升(单变量步)
定义
assumption_context.hpp:31
LMCAS::detail::node
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
定义
base.hpp:91
LMCAS::detail::numeric_failure
Result< ApproxReal > numeric_failure(CasErrc code, std::string message)
定义
numeric_evaluation.cpp:24
LMCAS::detail::numeric_approximation
Result< ApproxReal > numeric_approximation(double value)
定义
numeric_evaluation.cpp:28
LMCAS::integer
ExprResult integer(Integer)=delete
LMCAS::CasErrc::NumericFailure
@ NumericFailure
定义
result.hpp:27
LMCAS::CasErrc::DomainError
@ DomainError
定义
result.hpp:16
LMCAS::exponent
const ExprPtr & exponent
定义
expr.hpp:215
LMCAS::value
const std::string const ExprPtr & value
定义
expr.hpp:293
LMCAS::denominator
const ExprPtr & denominator
定义
expr.hpp:200
LMCAS::rational
ExprResult rational(const Rational &value)
定义
expr_values.cpp:82
numeric_evaluation_support.hpp
src
numeric_evaluation_power.cpp
生成于
, 为 LMCAS使用
1.18.0