LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
interp_shape.c
浏览该文件的文档.
1#include "memory_bridge.h"
2#include "internal.h"
4
5#include <math.h>
6#include <string.h>
7
14
16{
17 if (!p) {
18 return;
19 }
24}
25
26static lmmc_real_t interp_pchip_endpoint(lmmc_real_t h1, lmmc_real_t h2,
27 lmmc_real_t slope1, lmmc_real_t slope2)
28{
29 lmmc_real_t derivative = ((2.0 * h1 + h2) * slope1 - h1 * slope2) / (h1 + h2);
30 if (derivative * slope1 <= 0.0) {
31 return 0.0;
32 }
33 if (slope1 * slope2 <= 0.0 && fabs(derivative) > 3.0 * fabs(slope1)) {
34 return 3.0 * slope1;
35 }
36 return derivative;
37}
38
39static void interp_pchip_derivatives(lmmc_interp_pchip_t* p,
40 const lmmc_real_t* delta)
41{
42 const lmmc_real_t* xs = p->xs;
43 size_t i, n = p->n;
44 if (n == 2) {
45 p->d[0] = p->d[1] = delta[0];
46 return;
47 }
48 for (i = 1; i < n - 1; ++i) {
49 if (delta[i - 1] * delta[i] <= 0.0) {
50 p->d[i] = 0.0;
51 } else {
52 lmmc_real_t h1 = xs[i] - xs[i - 1];
53 lmmc_real_t h2 = xs[i + 1] - xs[i];
54 lmmc_real_t w1 = 2.0 * h2 + h1;
55 lmmc_real_t w2 = h2 + 2.0 * h1;
56 p->d[i] = (w1 + w2) / (w1 / delta[i - 1] + w2 / delta[i]);
57 }
58 }
59 p->d[0] = interp_pchip_endpoint(xs[1] - xs[0], xs[2] - xs[1], delta[0], delta[1]);
60 p->d[n - 1] = interp_pchip_endpoint(xs[n - 1] - xs[n - 2],
61 xs[n - 2] - xs[n - 3], delta[n - 2], delta[n - 3]);
62}
63
65 const lmmc_real_t* xs, const lmmc_real_t* ys, size_t n,
67{
68 lmmc_interp_pchip_t* p = NULL;
69 lmmc_real_t* delta = NULL;
70 size_t i;
71
72 if (!out) {
74 }
75 *out = NULL;
76 if (!interp_check_samples(xs, ys, n, 2)) {
78 }
79
80 p = (lmmc_interp_pchip_t*)lmmc_memory_alloc(sizeof(*p));
81 if (!p) {
83 }
84 p->n = n; p->xs = NULL; p->ys = NULL; p->d = NULL;
85
89 delta = (lmmc_real_t*)lmmc_memory_alloc_array(n - 1, sizeof(lmmc_real_t));
90 if (!p->xs || !p->ys || !p->d || !delta) {
91 lmmc_memory_free(delta);
94 }
95 memcpy(p->xs, xs, n * sizeof(lmmc_real_t));
96 memcpy(p->ys, ys, n * sizeof(lmmc_real_t));
97
98 for (i = 0; i < n - 1; i++) {
99 delta[i] = (ys[i + 1] - ys[i]) / (xs[i + 1] - xs[i]);
100 }
101
102 interp_pchip_derivatives(p, delta);
103 if (!interp_check_finite_values(delta, n - 1) ||
105 lmmc_memory_free(delta);
108 }
109
110 lmmc_memory_free(delta);
111 *out = p;
112 return LMMC_STATUS_OK;
113}
114
116 const lmmc_interp_pchip_t* p, lmmc_real_t x, lmmc_real_t* out_y)
117{
118 size_t seg;
119 lmmc_real_t h, t, a, b, result;
120 if (!p || !out_y || !isfinite(x)) {
122 }
123 if (x < p->xs[0] || x > p->xs[p->n - 1]) {
125 }
126 if (x == p->xs[p->n - 1]) {
127 *out_y = p->ys[p->n - 1];
128 return LMMC_STATUS_OK;
129 }
130
131 seg = interp_find_interval(p->xs, p->n, x);
132 h = p->xs[seg + 1] - p->xs[seg];
133 t = (x - p->xs[seg]) / h;
134
135 a = 1.0 - t;
136 b = t;
137 result = a * a * (1.0 + 2.0 * t) * p->ys[seg]
138 + b * b * (3.0 - 2.0 * t) * p->ys[seg + 1]
139 + t * a * a * h * p->d[seg]
140 - b * b * a * h * p->d[seg + 1];
141 if (!isfinite(result)) {
143 }
144 *out_y = result;
145 return LMMC_STATUS_OK;
146}
147
154
156{
157 if (!a) {
158 return;
159 }
164}
165
166static void interp_akima_derivatives(lmmc_interp_akima_t* a, lmmc_real_t* m)
167{
168 size_t i, n = a->n, nm1 = n - 1;
169 const lmmc_real_t* xs = a->xs;
170 const lmmc_real_t* ys = a->ys;
172 for (i = 0; i < nm1; i++) {
173 m[i + 2] = (ys[i + 1] - ys[i]) / (xs[i + 1] - xs[i]);
174 }
175
181 m[1] = 2.0 * m[2] - m[3];
182 m[0] = 2.0 * m[1] - m[2];
183 m[nm1 + 2] = 2.0 * m[nm1 + 1] - m[nm1];
184 m[nm1 + 3] = 2.0 * m[nm1 + 2] - m[nm1 + 1];
185
191 for (i = 0; i < n; i++) {
192 lmmc_real_t w1 = fabs(m[i + 3] - m[i + 2]);
193 lmmc_real_t w2 = fabs(m[i + 1] - m[i]);
194 if (w1 + w2 < 1e-30) {
196 a->d[i] = 0.5 * (m[i + 1] + m[i + 2]);
197 } else {
198 a->d[i] = (w1 * m[i + 1] + w2 * m[i + 2]) / (w1 + w2);
199 }
200 }
201}
202
204 const lmmc_real_t* xs, const lmmc_real_t* ys, size_t n,
206{
207 lmmc_interp_akima_t* a = NULL;
208 lmmc_real_t* m = NULL;
209 size_t slope_count;
210
211 if (!out) {
213 }
214 *out = NULL;
215 if (!interp_check_samples(xs, ys, n, 5)) {
217 }
218 if (!lmmc_safe_add_size(n, 3, &slope_count)) {
220 }
221
222
223 a = (lmmc_interp_akima_t*)lmmc_memory_alloc(sizeof(*a));
224 if (!a) {
226 }
227 a->n = n; a->xs = NULL; a->ys = NULL; a->d = NULL;
228
232 m = (lmmc_real_t*)lmmc_memory_alloc_array(slope_count, sizeof(lmmc_real_t));
233 if (!a->xs || !a->ys || !a->d || !m) {
237 }
238 memcpy(a->xs, xs, n * sizeof(lmmc_real_t));
239 memcpy(a->ys, ys, n * sizeof(lmmc_real_t));
240
241 interp_akima_derivatives(a, m);
242 if (!interp_check_finite_values(m, slope_count) ||
247 }
248
250 *out = a;
251 return LMMC_STATUS_OK;
252}
253
255 const lmmc_interp_akima_t* a, lmmc_real_t x, lmmc_real_t* out_y)
256{
257 size_t seg;
258 lmmc_real_t h, t, omt, result;
259 if (!a || !out_y || !isfinite(x)) {
261 }
262 if (x < a->xs[0] || x > a->xs[a->n - 1]) {
264 }
265 if (x == a->xs[a->n - 1]) {
266 *out_y = a->ys[a->n - 1];
267 return LMMC_STATUS_OK;
268 }
269
270 seg = interp_find_interval(a->xs, a->n, x);
271 h = a->xs[seg + 1] - a->xs[seg];
272 t = (x - a->xs[seg]) / h;
273 omt = 1.0 - t;
274
275 result = omt * omt * (1.0 + 2.0 * t) * a->ys[seg]
276 + t * t * (3.0 - 2.0 * t) * a->ys[seg + 1]
277 + t * omt * omt * h * a->d[seg]
278 - t * t * omt * h * a->d[seg + 1];
279 if (!isfinite(result)) {
281 }
282 *out_y = result;
283 return LMMC_STATUS_OK;
284}
double lmmc_real_t
Public and internal LMMC real type.
LMMC 内部使用的公共工具(仅源文件可见).
void lmmc_interp_pchip_destroy(lmmc_interp_pchip_t *p)
销毁 PCHIP 插值上下文,释放内部分配的所有内存.
lmmc_status_t lmmc_interp_akima_create(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, lmmc_interp_akima_t **out)
由节点构造 Akima 局部三次插值.
void lmmc_interp_akima_destroy(lmmc_interp_akima_t *a)
销毁 Akima 插值上下文,释放内部分配的所有内存.
lmmc_status_t lmmc_interp_pchip_create(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, lmmc_interp_pchip_t **out)
由节点构造 PCHIP 单调三次插值.
lmmc_status_t lmmc_interp_pchip_eval(const lmmc_interp_pchip_t *p, lmmc_real_t x, lmmc_real_t *out_y)
在 PCHIP 插值上求值.
lmmc_status_t lmmc_interp_akima_eval(const lmmc_interp_akima_t *a, lmmc_real_t x, lmmc_real_t *out_y)
在 Akima 插值上求值.
size_t interp_find_interval(const lmmc_real_t *xs, size_t n, lmmc_real_t query_x)
定义 interp.c:6
int interp_check_finite_values(const lmmc_real_t *values, size_t n)
int interp_check_samples(const lmmc_real_t *xs, const lmmc_real_t *ys, size_t n, size_t minimum)
Akima 插值上下文(不透明类型).
PCHIP 插值上下文(不透明类型).
void * lmmc_memory_alloc_array(size_t count, size_t element_size)
void * lmmc_memory_alloc(size_t size)
void lmmc_memory_free(void *pointer)
Private recoverable allocator for persistent LMMC ownership.
lmmc_status_t
LMMC 库统一返回的状态码.
@ LMMC_STATUS_OK
@ LMMC_STATUS_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT
@ LMMC_STATUS_OUT_OF_RANGE