LMCAS
Lamina Computer Algebra System
载入中...
搜索中...
未找到
numeric_evaluation_functions.cpp
浏览该文件的文档.
2#include "lmmc/numeric.h"
3#include <cmath>
4#include <optional>
5
6namespace LMCAS::detail {
7namespace {
8
9std::optional<Result<ApproxReal>> trigonometric(FunctionNode::FuncType type, double x) {
10 switch (type) {
12 return numeric_approximation(std::sin(x));
13 }
15 return numeric_approximation(std::cos(x));
16 }
18 return numeric_approximation(std::tan(x));
19 }
21 if (std::sin(x) == 0.0) {
22 return numeric_failure(CasErrc::DomainError, "cot is undefined");
23 }
24 return numeric_approximation(1.0 / std::tan(x));
25 }
27 if (std::cos(x) == 0.0) {
28 return numeric_failure(CasErrc::DomainError, "sec is undefined");
29 }
30 return numeric_approximation(1.0 / std::cos(x));
31 }
33 if (std::sin(x) == 0.0) {
34 return numeric_failure(CasErrc::DomainError, "csc is undefined");
35 }
36 return numeric_approximation(1.0 / std::sin(x));
37 }
38 default: {
39 return std::nullopt;
40 }
41 }
42}
43
44std::optional<Result<ApproxReal>> inverse_trigonometric(FunctionNode::FuncType type, double x) {
45 switch (type) {
47 if (x < -1.0 || x > 1.0) {
48 return numeric_failure(CasErrc::DomainError, "asin real domain is [-1, 1]");
49 }
50 return numeric_approximation(std::asin(x));
51 }
53 if (x < -1.0 || x > 1.0) {
54 return numeric_failure(CasErrc::DomainError, "acos real domain is [-1, 1]");
55 }
56 return numeric_approximation(std::acos(x));
57 }
59 return numeric_approximation(std::atan(x));
60 }
61 default: {
62 return std::nullopt;
63 }
64 }
65}
66
67std::optional<Result<ApproxReal>> hyperbolic(FunctionNode::FuncType type, double x) {
68 switch (type) {
70 return numeric_approximation(std::sinh(x));
71 }
73 return numeric_approximation(std::cosh(x));
74 }
76 return numeric_approximation(std::tanh(x));
77 }
78 default: {
79 return std::nullopt;
80 }
81 }
82}
83
84std::optional<Result<ApproxReal>> elementary(FunctionNode::FuncType type, double x) {
85 switch (type) {
88 if (x <= 0.0) {
89 return numeric_failure(CasErrc::DomainError, "logarithm requires a positive real argument");
90 }
91 return numeric_approximation(std::log(x));
92 }
94 return numeric_approximation(std::abs(x));
95 }
97 if (x < 0.0) {
98 return numeric_failure(CasErrc::DomainError, "real square root requires a non-negative argument");
99 }
100 return numeric_approximation(std::sqrt(x));
101 }
103 return numeric_approximation(std::exp(x));
104 }
106 return numeric_approximation((x > 0.0) - (x < 0.0));
107 }
109 return numeric_approximation(std::floor(x));
110 }
112 return numeric_approximation(std::ceil(x));
113 }
115 return numeric_approximation(std::round(x));
116 }
117 default: {
118 return std::nullopt;
119 }
120 }
121}
122
123std::optional<Result<ApproxReal>> special(FunctionNode::FuncType type, double x) {
124 switch (type) {
126 return numeric_approximation(std::erf(x));
127 }
129 lmmc_real_t value = 0.0;
130 const auto status = lmmc_lambertw(static_cast<lmmc_real_t>(x), &value);
131 if (status == LMMC_STATUS_INVALID_ARGUMENT) {
132 return numeric_failure(CasErrc::DomainError, "LambertW argument is outside the real branch");
133 }
134 if (status == LMMC_STATUS_CONVERGENCE_FAILED) {
135 return numeric_failure(CasErrc::NumericFailure, "LambertW failed to certify convergence");
136 }
137 if (status == LMMC_STATUS_NUMERICAL_FAILURE) {
138 return numeric_failure(CasErrc::NumericFailure, "LambertW encountered a nonfinite numerical value");
139 }
140 if (status != LMMC_STATUS_OK) {
141 return numeric_failure(CasErrc::InternalInvariant, "Unexpected LambertW status");
142 }
143 return numeric_approximation(static_cast<double>(value));
144 }
147 return numeric_approximation(x);
148 }
150 return numeric_approximation(std::atan2(0.0, x));
151 }
153 return numeric_approximation(0.0);
154 }
156 return numeric_approximation(std::abs(x));
157 }
158 default: {
159 return std::nullopt;
160 }
161 }
162}
163
164}
165
167 auto evaluated = trigonometric(type, x);
168 if (!evaluated) {
169 evaluated = inverse_trigonometric(type, x);
170 }
171 if (!evaluated) {
172 evaluated = hyperbolic(type, x);
173 }
174 if (!evaluated) {
175 evaluated = elementary(type, x);
176 }
177 if (!evaluated) {
178 evaluated = special(type, x);
179 }
180 if (!evaluated) {
182 "function is not supported by real numeric evaluation");
183 }
184 return std::move(*evaluated);
185}
186
187}
@ Sqrt
对数、绝对值、平方根。
@ Round
四舍五入 round(x)。
@ ComplexArg
复数辐角 arg(z)。
@ Erf
误差函数 erf(x) = (2/√π)∫₀ˣ e^(-t²) dt。
@ Sgn
符号函数 sgn(x) ∈ {-1, 0, 1}。
std::optional< Result< ApproxReal > > elementary(FunctionNode::FuncType type, double x)
std::optional< Result< ApproxReal > > hyperbolic(FunctionNode::FuncType type, double x)
std::optional< Result< ApproxReal > > special(FunctionNode::FuncType type, double x)
std::optional< Result< ApproxReal > > inverse_trigonometric(FunctionNode::FuncType type, double x)
std::optional< Result< ApproxReal > > trigonometric(FunctionNode::FuncType type, double x)
多元 Hensel 提升(单变量步)
Result< ApproxReal > numeric_failure(CasErrc code, std::string message)
Result< ApproxReal > evaluate_unary_numeric(FunctionNode::FuncType type, double value)
Result< ApproxReal > numeric_approximation(double value)
const std::string const ExprPtr & value