LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
numeric_evaluation_nodes.cpp
浏览该文件的文档.
3#include <algorithm>
4#include <cmath>
5
6namespace LMCAS::detail {
7
9 double value = 0.0;
10 try {
11 if (std::holds_alternative<BigInt>(node.value())) {
12 value = std::get<BigInt>(node.value()).to_double();
13 } else {
14 value = std::get<Rational>(node.value()).to_double();
15 }
16 } catch (const std::exception& error) {
17 return numeric_failure(CasErrc::NumericFailure, error.what());
18 }
19 if (!std::isfinite(value)) {
21 "exact number cannot be represented as a finite double");
22 }
24}
25
27 if (node.is_constant() && (node.name() == "pi" || node.name() == "π")) {
28 return numeric_approximation(static_cast<double>(LMMC_CONST_PI));
29 }
30 if (node.is_constant() && node.name() == "e") {
31 return numeric_approximation(std::exp(1.0));
32 }
33 if (node.is_constant() && node.name() == "phi") {
34 return numeric_approximation((1.0 + std::sqrt(5.0)) / 2.0);
35 }
36 auto it = bindings_.find(node.name());
37 if (it == bindings_.end()) {
39 "no numeric binding for symbol '" + node.name() + "'");
40 }
41 if (!std::isfinite(it->second)) {
42 return numeric_failure(CasErrc::NumericFailure, "numeric binding is not finite");
43 }
45 ApproxReal{it->second, 0.0, NumericStatus::Finite});
46}
47
49 double value = 0.0;
50 bool infinite = false;
51 for (const auto& operand : node.operands()) {
52 auto evaluated = evaluate(operand);
53 if (!evaluated) return evaluated;
54 value += evaluated.value().value;
55 infinite = infinite || !evaluated.value().is_finite();
56 if (std::isinf(value) && !infinite) {
57 return numeric_failure(CasErrc::NumericFailure, "numeric evaluation produced a nonfinite result");
58 }
59 }
60 if (std::isinf(value) && infinite) {
63 }
65}
66
68 const bool exact_constants = std::all_of(node.operands().begin(), node.operands().end(),
69 [](const auto& operand) {
70 if (dynamic_cast<const NumberNode*>(operand.get())) return true;
71 const auto* power = dynamic_cast<const PowerNode*>(operand.get());
72 const auto* exponent = power
73 ? dynamic_cast<const NumberNode*>(power->exponent().get()) : nullptr;
74 return exponent && exponent->is_negative_one() &&
75 dynamic_cast<const NumberNode*>(power->base().get());
76 });
77 if (exact_constants) {
78 Rational value(1);
79 for (const auto& operand : node.operands()) {
80 const auto* power = dynamic_cast<const PowerNode*>(operand.get());
81 const auto* number = dynamic_cast<const NumberNode*>(
82 power ? power->base().get() : operand.get());
83 auto step = context_.consume_steps(power ? 3 : 1, "evaluate_numeric");
84 if (!step) return Result<ApproxReal>::failure(step.error());
85 Rational factor = std::holds_alternative<BigInt>(number->value())
86 ? Rational(std::get<BigInt>(number->value()))
87 : std::get<Rational>(number->value());
88 if (power) {
89 if (factor.is_zero()) {
90 return numeric_failure(CasErrc::DomainError, "zero cannot be raised to a non-positive power");
91 }
92 factor = Rational(factor.get_denominator(), factor.get_numerator());
93 }
94 value = value * factor;
95 auto numerator_bits = context_.require_integer_bits(
96 value.get_numerator().bit_length(), "evaluate_numeric");
97 if (!numerator_bits) return Result<ApproxReal>::failure(numerator_bits.error());
98 auto denominator_bits = context_.require_integer_bits(
99 value.get_denominator().bit_length(), "evaluate_numeric");
100 if (!denominator_bits) return Result<ApproxReal>::failure(denominator_bits.error());
101 }
102 try {
103 return numeric_approximation(value.to_double());
104 } catch (const std::exception& error) {
105 return numeric_failure(CasErrc::NumericFailure, error.what());
106 }
107 }
108 double value = 1.0;
109 bool infinite = false;
110 for (const auto& operand : node.operands()) {
111 auto evaluated = evaluate(operand);
112 if (!evaluated) return evaluated;
113 const double factor = evaluated.value().value;
114 const double multiplied = value * factor;
115 if (multiplied == 0.0 && value != 0.0 && factor != 0.0) {
116 return numeric_failure(CasErrc::NumericFailure, "numeric multiplication underflow");
117 }
118 value = multiplied;
119 infinite = infinite || !evaluated.value().is_finite();
120 if (std::isinf(value) && !infinite) {
121 return numeric_failure(CasErrc::NumericFailure, "numeric evaluation produced a nonfinite result");
122 }
123 }
124 if (std::isinf(value) && infinite) {
127 }
129}
130
132 if (node.arguments().size() != 2) {
133 return numeric_failure(CasErrc::InvalidArgument, "atan2 requires two arguments");
134 }
135 auto y = evaluate(node.arguments()[0]);
136 if (!y) return y;
137 auto x = evaluate(node.arguments()[1]);
138 if (!x) return x;
139 return numeric_approximation(std::atan2(y.value().value, x.value().value));
140}
141
143 if (node.arguments().empty()) {
144 return numeric_failure(CasErrc::InvalidArgument, "min/max requires an argument");
145 }
146 auto first = evaluate(node.arguments().front());
147 if (!first) return first;
148 double value = first.value().value;
149 for (std::size_t i = 1; i < node.arguments().size(); ++i) {
150 auto next = evaluate(node.arguments()[i]);
151 if (!next) return next;
153 ? std::max(value, next.value().value)
154 : std::min(value, next.value().value);
155 }
157}
158
159Result<ApproxReal> NumericEvaluator::norm(const std::array<const PowerNode*, 2>& squares) {
160 auto first = evaluate(squares[0]->base());
161 if (!first) return first;
162 if (!squares[1]) return numeric_approximation(std::abs(first.value().value));
163 auto second = evaluate(squares[1]->base());
164 if (!second) return second;
165 return numeric_approximation(std::hypot(first.value().value, second.value().value));
166}
167
168Result<ApproxReal> NumericEvaluator::root(const std::shared_ptr<const SymbolicNode>& node) {
169 auto root_expression = LMCAS::detail::make_expression_ptr(node);
170 auto root = rootof_evaluate_checked(root_expression, context_);
171 if (!root) return Result<ApproxReal>::failure(root.error());
172 return numeric_approximation(root.value());
173}
174
175}
加法节点,表示多个操作数的求和。
Result< void > consume_steps(std::size_t amount=1, const std::string &operation={})
Result< void > require_integer_bits(std::size_t amount, const std::string &operation={}) const
函数节点,表示数学函数调用(三角函数、对数、特殊函数等)。
@ Max
最大值 max(a, b)。
乘法节点,表示多个操作数的乘积。
幂运算节点,表示 base^exponent。
static Result failure(CasErrc code, std::string message, std::string operation={})
static Result success(T value)
变量节点,表示一个符号变量。
Result< ApproxReal > variable(const VariableNode &node)
Result< ApproxReal > sum(const AddNode &node)
Result< ApproxReal > norm(const std::array< const PowerNode *, 2 > &squares)
Result< ApproxReal > number(const NumberNode &node)
Result< ApproxReal > extremum(const FunctionNode &node)
Result< ApproxReal > root(const std::shared_ptr< const SymbolicNode > &node)
Result< ApproxReal > atan2(const FunctionNode &node)
Result< ApproxReal > evaluate(const std::shared_ptr< const SymbolicNode > &node)
Result< ApproxReal > power(const PowerNode &node)
Result< ApproxReal > product(const MultiplyNode &node)
多元 Hensel 提升(单变量步)
std::shared_ptr<::LMCAS::SymbolicExpr > make_expression_ptr(SymbolicNodePtr root)
const SymbolicNodePtr & node(const ::LMCAS::SymbolicExpr &expression) noexcept
Result< ApproxReal > numeric_failure(CasErrc code, std::string message)
Result< ApproxReal > numeric_approximation(double value)
RootOfEvaluationResult rootof_evaluate_checked(const std::shared_ptr< SymbolicExpr > &rootof_expr, ComputationContext &context)
const std::string const ExprPtr & value
精确 RootOf 标识构造及受检数值求值。