LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
nonlinear_newton.c
浏览该文件的文档.
2
13
14static lmmc_status_t newton_derivative(newton_state_t* s, lmmc_real_t* derivative) {
15 if (s->dfunc != NULL) {
16 *derivative = s->dfunc(s->x, s->user_data);
17 } else {
18 lmmc_real_t abs_x = lmmc_abs(s->x);
19 lmmc_real_t one = 1.0;
20 lmmc_real_t max_val = lmmc_max(abs_x, one);
21 lmmc_real_t h = 0.0;
22 lmmc_real_t f_plus = 0.0;
23 lmmc_real_t f_minus = 0.0;
24 lmmc_real_t x_plus_h = 0.0;
25 lmmc_real_t x_minus_h = 0.0;
26 lmmc_real_t f_diff = 0.0;
27 lmmc_real_t two_h = 0.0;
28 lmmc_real_t two = 2.0;
29
30 LMMC_REAL_MUL(&h, &s->local_cfg.derivative_step, &max_val);
31
32 if (!lmmc_is_finite(&h) || h <= 0.0) {
33 s->out_result->num_iter = s->iter;
36 }
37
38 LMMC_REAL_ADD(&x_plus_h, &s->x, &h);
39 LMMC_REAL_SUB(&x_minus_h, &s->x, &h);
40 f_plus = s->func(x_plus_h, s->user_data);
41 f_minus = s->func(x_minus_h, s->user_data);
42
43 if (!lmmc_is_finite(&f_plus) || !lmmc_is_finite(&f_minus)) {
44 s->out_result->num_iter = s->iter;
47 }
48
49 LMMC_REAL_SUB(&f_diff, &f_plus, &f_minus);
50 LMMC_REAL_MUL(&two_h, &two, &h);
51 LMMC_REAL_DIV(derivative, &f_diff, &two_h);
52 }
53
54 if (!lmmc_is_finite(derivative)) {
55 s->out_result->num_iter = s->iter;
58 }
59
60 if (lmmc_abs(*derivative) < s->local_cfg.min_derivative) {
61 s->out_result->num_iter = s->iter;
64 }
65 return LMMC_STATUS_OK;
66}
67
68static lmmc_status_t newton_iteration(newton_state_t* s) {
69 lmmc_real_t derivative = 0.0;
70 lmmc_real_t step = 0.0;
71 lmmc_real_t x_next = 0.0;
72 lmmc_real_t f_next = 0.0;
73 lmmc_real_t x_tol = 0.0;
74
75 lmmc_status_t st = newton_derivative(s, &derivative);
76 if (st != LMMC_STATUS_OK) { return st; }
77 LMMC_REAL_DIV(&step, &s->fx, &derivative);
78 LMMC_REAL_SUB(&x_next, &s->x, &step);
79
80 if (!lmmc_is_finite(&step) || !lmmc_is_finite(&x_next)) {
81 s->out_result->num_iter = s->iter;
84 }
85
86 f_next = s->func(x_next, s->user_data);
87 if (!lmmc_is_finite(&f_next)) {
88 s->out_result->num_iter = s->iter;
91 }
92
93 if (lmmc_nonlinear_x_tolerance(x_next, &s->local_cfg, &x_tol) != LMMC_STATUS_OK) {
94 s->out_result->num_iter = s->iter;
97 }
98
99 s->out_result->num_iter = s->iter;
100 s->out_result->root = x_next;
101 s->out_result->function_value = f_next;
102 s->out_result->residual_norm = lmmc_abs(f_next);
103
105
106 {
107 lmmc_real_t x_diff = 0.0;
108 LMMC_REAL_SUB(&x_diff, &x_next, &s->x);
109 if (s->out_result->residual_norm <= s->local_cfg.abs_tol || lmmc_abs(x_diff) <= x_tol) {
110 s->out_result->converged = 1;
112 return LMMC_STATUS_OK;
113 }
114 }
115
116 if (lmmc_abs(step) < s->local_cfg.min_step) {
119 }
120
121 s->x = x_next;
122 s->fx = f_next;
123 return LMMC_STATUS_OK;
124}
125
129 void* user_data,
130 lmmc_real_t x0,
131 const lmmc_nonlinear_config_t* cfg,
132 lmmc_nonlinear_result_t* out_result
133) {
134 newton_state_t state = {0};
135 newton_state_t* s = &state;
136 s->func = func;
137 s->dfunc = dfunc;
138 s->user_data = user_data;
139 s->out_result = out_result;
140 s->x = x0;
141 if (s->func == NULL || s->out_result == NULL || !lmmc_is_finite(&x0)) {
143 }
144
146
147 {
149 if (st_cfg != LMMC_STATUS_OK) {
150 return st_cfg;
151 }
152 }
153
154 s->fx = s->func(s->x, s->user_data);
155 if (!lmmc_is_finite(&s->fx)) {
158 }
159
160 s->out_result->root = s->x;
162 s->out_result->residual_norm = lmmc_abs(s->fx);
163
165
167 s->out_result->converged = 1;
169 return LMMC_STATUS_OK;
170 }
171 for (s->iter = 1; s->iter <= s->local_cfg.max_iter; ++s->iter) {
172 lmmc_status_t st = newton_iteration(s);
173 if (st != LMMC_STATUS_OK || out_result->converged) { return st; }
174 }
175 s->out_result->converged = 0;
178}
#define LMMC_REAL_ADD(res, a, b)
计算 *res = *a + *b 。
#define LMMC_REAL_DIV(res, a, b)
计算 *res = *a / *b 。
#define LMMC_REAL_SUB(res, a, b)
计算 *res = *a - *b 。
double lmmc_real_t
Public and internal LMMC real type.
#define LMMC_REAL_MUL(res, a, b)
计算 *res = *a * *b 。
@ LMMC_NONLINEAR_FAILURE_NONE
@ LMMC_NONLINEAR_FAILURE_ZERO_DERIVATIVE
@ LMMC_NONLINEAR_FAILURE_SINGULAR_STEP
@ LMMC_NONLINEAR_FAILURE_MAX_ITER
@ LMMC_NONLINEAR_FAILURE_NUMERICAL_ISSUE
lmmc_real_t(*) lmmc_scalar_dfunc_t(lmmc_real_t x, void *user_data)
标量函数导数签名: ,与 lmmc_scalar_func_t 同形参.
lmmc_nonlinear_failure_t failure_reason
lmmc_status_t lmmc_newton_solve(lmmc_scalar_func_t func, lmmc_scalar_dfunc_t dfunc, void *user_data, lmmc_real_t x0, const lmmc_nonlinear_config_t *cfg, lmmc_nonlinear_result_t *out_result)
Newton 法求根.
lmmc_real_t(*) lmmc_scalar_func_t(lmmc_real_t x, void *user_data)
标量函数签名: .
求根算法配置.
求根结果统计.
void lmmc_nonlinear_do_log(const lmmc_nonlinear_config_t *cfg, size_t iter, lmmc_real_t x, lmmc_real_t f_x)
lmmc_status_t lmmc_nonlinear_x_tolerance(lmmc_real_t x, const lmmc_nonlinear_config_t *cfg, lmmc_real_t *out_x_tol)
void lmmc_nonlinear_reset_result(lmmc_nonlinear_result_t *out_result)
lmmc_status_t lmmc_nonlinear_load_and_validate_config(const lmmc_nonlinear_config_t *cfg, lmmc_nonlinear_config_t *out_cfg)
lmmc_scalar_dfunc_t dfunc
lmmc_nonlinear_result_t * out_result
lmmc_scalar_func_t func
lmmc_nonlinear_config_t local_cfg
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_INVALID_ARGUMENT