LMMC
Lamina Mathematic core
载入中...
搜索中...
未找到
complex.c
浏览该文件的文档.
1
5#include <float.h>
6#include <math.h>
7#include <string.h>
8#include "memory_bridge.h"
9#include "internal.h"
10#include "lmmc/config.h"
11#include "lmmc/complex.h"
12
13static int lmmc_complex_is_finite(const lmmc_complex_t* z)
14{
15 return isfinite(z->real) && isfinite(z->imag);
16}
17
18static lmmc_status_t lmmc_complex_finite_result(const lmmc_complex_t* z)
19{
20 return lmmc_complex_is_finite(z)
23}
24
26{
27 if (out == NULL || !isfinite(real) || !isfinite(imag)) {
29 }
30 LMMC_REAL_SET(&out->real, &real);
31 LMMC_REAL_SET(&out->imag, &imag);
32 return LMMC_STATUS_OK;
33}
34
36{
37 lmmc_real_t cos_theta, sin_theta;
38
39 if (out == NULL || !isfinite(r) || !isfinite(theta) || r < 0.0) {
41 }
42 if (r == 0.0) {
43 out->real = 0.0;
44 out->imag = 0.0;
45 return LMMC_STATUS_OK;
46 }
47
48 cos_theta = cos(theta);
49 sin_theta = sin(theta);
50 out->real = r * cos_theta;
51 out->imag = r * sin_theta;
52 return isfinite(out->real) && isfinite(out->imag)
55}
56
58{
59 if (a == NULL || b == NULL || out == NULL) {
61 }
62 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
64 }
65 LMMC_REAL_ADD(&out->real, &a->real, &b->real);
66 LMMC_REAL_ADD(&out->imag, &a->imag, &b->imag);
67 return lmmc_complex_finite_result(out);
68}
69
71{
72 if (a == NULL || b == NULL || out == NULL) {
74 }
75 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
77 }
78 LMMC_REAL_SUB(&out->real, &a->real, &b->real);
79 LMMC_REAL_SUB(&out->imag, &a->imag, &b->imag);
80 return lmmc_complex_finite_result(out);
81}
82
91static double lmmc_scaled_sum_products(double a, double b, int ep,
92 double c, double d, int eq, int* scale)
93{
94 const double p = a * b;
95 const double q = c * d;
96 *scale = p == 0.0 ? eq : q == 0.0 ? ep : ep > eq ? ep : eq;
97 const double sum = scalbn(p, ep - *scale) + scalbn(q, eq - *scale);
98 const double residual = scalbn(fma(a, b, -p), ep - *scale) +
99 scalbn(fma(c, d, -q), eq - *scale);
100 return sum + residual;
101}
102
103static int lmmc_products_are_normal(double p, double q)
104{
105 return isfinite(p) && isfinite(q) &&
106 fabs(p) >= DBL_MIN && fabs(q) >= DBL_MIN;
107}
108
123static double lmmc_sum_products(double a, double b, double c, double d)
124{
125 const double p = a * b;
126 const double q = c * d;
127 int ea, eb, ec, ed;
128 double ma, mb, mc, md;
129 int scale;
130
131 if (a == 0.0 || b == 0.0 || c == 0.0 || d == 0.0) {
132 return p + q;
133 }
134 if (lmmc_products_are_normal(p, q)) {
135 const double sum = fma(a, b, q) + fma(c, d, -q);
136 if (isfinite(sum) && fabs(sum) >= DBL_MIN) {
137 return sum;
138 }
139 }
140 ma = frexp(a, &ea);
141 mb = frexp(b, &eb);
142 mc = frexp(c, &ec);
143 md = frexp(d, &ed);
144 const double sum = lmmc_scaled_sum_products(ma, mb, ea + eb,
145 mc, md, ec + ed, &scale);
146 return scalbn(sum, scale);
147}
148
150{
151 lmmc_complex_t result;
152
153 if (a == NULL || b == NULL || out == NULL) {
155 }
156 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
158 }
159
160 result.real = lmmc_sum_products(a->real, b->real, -a->imag, b->imag);
161 result.imag = lmmc_sum_products(a->real, b->imag, a->imag, b->real);
162 if (!lmmc_complex_is_finite(&result)) {
164 }
165 *out = result;
166 return LMMC_STATUS_OK;
167}
168
170{
171 int ea, eb, ec, ed;
172 int denominator_scale, real_scale, imag_scale;
173 lmmc_complex_t result;
174
175 if (a == NULL || b == NULL || out == NULL) {
177 }
178 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
180 }
181 if (b->real == 0.0 && b->imag == 0.0) {
183 }
184
185 const double ma = frexp(a->real, &ea);
186 const double mb = frexp(a->imag, &eb);
187 const double mc = frexp(b->real, &ec);
188 const double md = frexp(b->imag, &ed);
189 const double denominator = lmmc_scaled_sum_products(
190 mc, mc, ec + ec, md, md, ed + ed, &denominator_scale);
191 const double real = lmmc_scaled_sum_products(
192 ma, mc, ea + ec, mb, md, eb + ed, &real_scale);
193 const double imag = lmmc_scaled_sum_products(
194 mb, mc, eb + ec, -ma, md, ea + ed, &imag_scale);
195 result.real = scalbn(real / denominator, real_scale - denominator_scale);
196 result.imag = scalbn(imag / denominator, imag_scale - denominator_scale);
197 if (!lmmc_complex_is_finite(&result)) {
199 }
200 *out = result;
201 return LMMC_STATUS_OK;
202}
203
205{
206 if (z == NULL || out == NULL) {
208 }
209 if (!lmmc_complex_is_finite(z)) {
211 }
212 LMMC_REAL_SET(&out->real, &z->real);
213 LMMC_REAL_NEG(&out->imag, &z->imag);
214 return lmmc_complex_finite_result(out);
215}
216
218{
219 lmmc_real_t modulus;
220
221 if (z == NULL || out == NULL) {
223 }
224 if (!lmmc_complex_is_finite(z)) {
226 }
227 modulus = hypot(z->real, z->imag);
228 if (!isfinite(modulus)) {
230 }
231 *out = modulus;
232 return LMMC_STATUS_OK;
233}
234
236{
237 if (z == NULL || out == NULL) {
239 }
240 if (!lmmc_complex_is_finite(z)) {
242 }
243 LMMC_REAL_ATAN2(out, &z->imag, &z->real);
244 return isfinite(*out) ? LMMC_STATUS_OK : LMMC_STATUS_NUMERICAL_FAILURE;
245}
246
248{
249 lmmc_real_t ex, cos_y, sin_y;
250 lmmc_complex_t result;
251
252 if (z == NULL || out == NULL) {
254 }
255 if (!lmmc_complex_is_finite(z)) {
257 }
258
260 LMMC_REAL_EXP(&ex, &z->real);
261 LMMC_REAL_COS(&cos_y, &z->imag);
262 LMMC_REAL_SIN(&sin_y, &z->imag);
263 if (!isfinite(ex) || ex < DBL_MIN) {
264 /* e^(x/2) factors carry the scale through each trigonometric product. */
265 ex = exp(z->real * 0.5);
266 result.real = (ex * cos_y) * ex;
267 result.imag = (ex * sin_y) * ex;
268 } else {
269 LMMC_REAL_MUL(&result.real, &ex, &cos_y);
270 LMMC_REAL_MUL(&result.imag, &ex, &sin_y);
271 }
272 if (!lmmc_complex_is_finite(&result)) {
274 }
275 *out = result;
276 return LMMC_STATUS_OK;
277}
278
279
281{
282 lmmc_real_t major;
283 lmmc_real_t minor;
284 lmmc_real_t ratio;
285 lmmc_complex_t result;
286
287 if (z == NULL || out == NULL) {
289 }
290 if (!lmmc_complex_is_finite(z)) {
292 }
293 if (z->real == 0.0 && z->imag == 0.0) {
295 }
296
297 major = fmax(fabs(z->real), fabs(z->imag));
298 minor = fmin(fabs(z->real), fabs(z->imag));
299 if (major >= 0.5 && major <= 1.0) {
308 const double major_squared = major * major;
309 const double minor_squared = minor * minor;
310 const double sum = major_squared + minor_squared;
311 const double sum_error = (major_squared - sum) + minor_squared;
312 const double major_error = fma(major, major, -major_squared);
313 const double minor_error = fma(minor, minor, -minor_squared);
314 double tail_a, tail_b, tail_c;
315 double correction = lmmc_two_sum(sum_error, major_error, &tail_a);
316 correction = lmmc_two_sum(correction, minor_error, &tail_b);
317 const double delta = lmmc_two_sum(sum - 1.0, correction, &tail_c);
318 result.real = 0.5 * log1p(delta + ((tail_a + tail_b) + tail_c));
319 } else {
320 ratio = minor / major;
321 result.real = log(major) + 0.5 * log1p(ratio * ratio);
322 }
323 result.imag = atan2(z->imag, z->real);
324 if (!lmmc_complex_is_finite(&result)) {
326 }
327 *out = result;
328 return LMMC_STATUS_OK;
329}
330
332{
333 lmmc_real_t scale;
334 lmmc_real_t scaled_magnitude;
335 lmmc_real_t component;
336 lmmc_complex_t result;
337
338 if (z == NULL || out == NULL) {
340 }
341 if (!lmmc_complex_is_finite(z)) {
343 }
344
345 if (z->imag == 0.0) {
346 if (z->real < 0.0) {
347 result.real = 0.0;
348 result.imag = copysign(sqrt(-z->real), z->imag);
349 } else {
350 result.real = sqrt(fabs(z->real));
351 result.imag = copysign(0.0, z->imag);
352 }
353 *out = result;
354 return LMMC_STATUS_OK;
355 }
356
357 scale = fmax(fabs(z->real), fabs(z->imag));
358 scaled_magnitude = hypot(z->real / scale, z->imag / scale);
359 if (z->real >= 0.0) {
360 component = sqrt(scale) *
361 sqrt(0.5 * (scaled_magnitude + z->real / scale));
362 result.real = component;
363 result.imag = z->imag / (2.0 * component);
364 } else {
365 component = sqrt(scale) *
366 sqrt(0.5 * (scaled_magnitude - z->real / scale));
367 result.real = fabs(z->imag) / (2.0 * component);
368 result.imag = copysign(component, z->imag);
369 }
370 if (!lmmc_complex_is_finite(&result)) {
372 }
373 *out = result;
374 return LMMC_STATUS_OK;
375}
376
386static lmmc_complex_t lmmc_complex_hyperbolic_products(double even, double odd, double y)
387{
388 const double cosh_y = cosh(y);
389 const double sinh_y = sinh(y);
390 lmmc_complex_t result;
391
392 if (isfinite(cosh_y) && isfinite(sinh_y)) {
393 result.real = even * cosh_y;
394 result.imag = odd * sinh_y;
395 } else {
396 const double scale = exp(fabs(y) * 0.5);
397 const double half_scale = scale * 0.5;
398 result.real = (even * half_scale) * scale;
399 result.imag = (odd * copysign(half_scale, y)) * scale;
400 }
401 return result;
402}
403
405{
406 lmmc_real_t sin_x, cos_x;
407 lmmc_complex_t result;
408
409 if (z == NULL || out == NULL) {
411 }
412 if (!lmmc_complex_is_finite(z)) {
414 }
415
417 LMMC_REAL_SIN(&sin_x, &z->real);
418 LMMC_REAL_COS(&cos_x, &z->real);
419
420 result = lmmc_complex_hyperbolic_products(sin_x, cos_x, z->imag);
421 if (!lmmc_complex_is_finite(&result)) {
423 }
424 *out = result;
425 return LMMC_STATUS_OK;
426}
427
429{
430 lmmc_real_t cos_x, sin_x;
431 lmmc_complex_t result;
432
433 if (z == NULL || out == NULL) {
435 }
436 if (!lmmc_complex_is_finite(z)) {
438 }
439
441 LMMC_REAL_COS(&cos_x, &z->real);
442 LMMC_REAL_SIN(&sin_x, &z->real);
443
444 result = lmmc_complex_hyperbolic_products(cos_x, -sin_x, z->imag);
445 if (!lmmc_complex_is_finite(&result)) {
447 }
448 *out = result;
449 return LMMC_STATUS_OK;
450}
451
462static lmmc_status_t lmmc_complex_integer_power(const lmmc_complex_t* base,
463 double exponent, lmmc_complex_t* out)
464{
465 const lmmc_complex_t one = {1.0, 0.0};
466 lmmc_complex_t factor = *base;
467 lmmc_complex_t result = one;
468 lmmc_status_t st;
469 double remaining = fabs(exponent);
470 int has_product = 0;
471
472 if (exponent < 0.0) {
473 st = lmmc_complex_div(&one, base, &factor);
474 if (st != LMMC_STATUS_OK) {
475 return st;
476 }
477 }
478 while (remaining != 0.0) {
479 if (fmod(remaining, 2.0) != 0.0) {
480 if (!has_product) {
481 result = factor;
482 has_product = 1;
483 } else {
484 st = lmmc_complex_mul(&result, &factor, &result);
485 if (st != LMMC_STATUS_OK) {
486 return st;
487 }
488 }
489 }
490 remaining = floor(remaining * 0.5);
491 if (remaining != 0.0) {
492 st = lmmc_complex_mul(&factor, &factor, &factor);
493 if (st != LMMC_STATUS_OK) {
494 return st;
495 }
496 }
497 }
498 *out = result;
499 return LMMC_STATUS_OK;
500}
501
502static lmmc_status_t lmmc_complex_zero_power(
503 const lmmc_complex_t* exp, lmmc_complex_t* out)
504{
505 lmmc_complex_t result;
506 if (exp->real == 0.0 && exp->imag == 0.0) {
507 result.real = 1.0;
508 } else if (exp->real > 0.0) {
509 result.real = 0.0;
510 } else {
512 }
513 result.imag = 0.0;
514 *out = result;
515 return LMMC_STATUS_OK;
516}
517
519{
520 lmmc_complex_t log_base, exp_times_log, result;
521 lmmc_status_t st;
522
523 if (base == NULL || exp == NULL || out == NULL) {
525 }
526
527 if (!lmmc_complex_is_finite(base) || !lmmc_complex_is_finite(exp)) {
529 }
530
531 if (base->real == 0.0 && base->imag == 0.0) {
532 return lmmc_complex_zero_power(exp, out);
533 }
534
535 if (exp->imag == 0.0 && trunc(exp->real) == exp->real) {
536 return lmmc_complex_integer_power(base, exp->real, out);
537 }
538
539 /* pow(base, exp) = exp(exp * log(base)) */
540 st = lmmc_complex_log(base, &log_base);
541 if (st != LMMC_STATUS_OK) {
542 return st;
543 }
544
545 st = lmmc_complex_mul(exp, &log_base, &exp_times_log);
546 if (st != LMMC_STATUS_OK) {
547 return st;
548 }
549
550 st = lmmc_complex_exp(&exp_times_log, &result);
551 if (st != LMMC_STATUS_OK) {
552 return st;
553 }
554 *out = result;
555 return LMMC_STATUS_OK;
556}
557
559{
560 size_t n_bytes;
561 lmmc_complex_t* data;
562
563 if (out == NULL || size == 0) {
565 }
566
567 if (!lmmc_safe_mul_size(size, sizeof(lmmc_complex_t), &n_bytes)) {
569 }
570
571 data = (lmmc_complex_t*)lmmc_memory_alloc(n_bytes);
572 if (data == NULL) {
574 }
575 memset(data, 0, n_bytes);
576
577 out->size = size;
578 out->data = data;
579 out->owns_data = 1;
580 return LMMC_STATUS_OK;
581}
582
583lmmc_status_t lmmc_cmat_create(size_t rows, size_t cols, lmmc_cmat_t* out)
584{
585 size_t n_elem, n_bytes;
586 lmmc_complex_t* data;
587
588 if (out == NULL || rows == 0 || cols == 0) {
590 }
591
592 if (!lmmc_safe_mul_size(rows, cols, &n_elem)) {
594 }
595 if (!lmmc_safe_mul_size(n_elem, sizeof(lmmc_complex_t), &n_bytes)) {
597 }
598
599 data = (lmmc_complex_t*)lmmc_memory_alloc(n_bytes);
600 if (data == NULL) {
602 }
603 memset(data, 0, n_bytes);
604
605 out->rows = rows;
606 out->cols = cols;
607 out->stride = cols;
608 out->data = data;
609 out->owns_data = 1;
610 return LMMC_STATUS_OK;
611}
612
614{
615 if (vec == NULL) {
616 return;
617 }
618 if (vec->owns_data && vec->data != NULL) {
620 }
621 vec->data = NULL;
622 vec->size = 0;
623 vec->owns_data = 0;
624}
625
627{
628 if (mat == NULL) {
629 return;
630 }
631 if (mat->owns_data && mat->data != NULL) {
633 }
634 mat->data = NULL;
635 mat->rows = 0;
636 mat->cols = 0;
637 mat->stride = 0;
638 mat->owns_data = 0;
639}
复数类型与运算模块.
lmmc_status_t lmmc_complex_sin(const lmmc_complex_t *z, lmmc_complex_t *out)
复数正弦: .
lmmc_status_t lmmc_complex_exp(const lmmc_complex_t *z, lmmc_complex_t *out)
复数指数函数: ,其中 .
lmmc_status_t lmmc_complex_add(const lmmc_complex_t *a, const lmmc_complex_t *b, lmmc_complex_t *out)
复数加法: .
lmmc_complex_t * data
lmmc_status_t lmmc_complex_create(lmmc_real_t real, lmmc_real_t imag, lmmc_complex_t *out)
从笛卡尔坐标构造复数.
lmmc_status_t lmmc_complex_cos(const lmmc_complex_t *z, lmmc_complex_t *out)
复数余弦: .
lmmc_status_t lmmc_complex_conj(const lmmc_complex_t *z, lmmc_complex_t *out)
复数共轭: .
lmmc_status_t lmmc_cvec_create(size_t size, lmmc_cvec_t *out)
分配并初始化一个长度为 size 的复数向量,所有元素置零.
lmmc_status_t lmmc_complex_arg(const lmmc_complex_t *z, lmmc_real_t *out)
复数辐角: .
lmmc_status_t lmmc_complex_mul(const lmmc_complex_t *a, const lmmc_complex_t *b, lmmc_complex_t *out)
复数乘法: .
lmmc_status_t lmmc_cmat_create(size_t rows, size_t cols, lmmc_cmat_t *out)
分配并初始化一个 rows x cols 的复数矩阵,所有元素置零.
lmmc_status_t lmmc_complex_pow(const lmmc_complex_t *base, const lmmc_complex_t *exp, lmmc_complex_t *out)
复数幂: .
lmmc_complex_t * data
lmmc_status_t lmmc_complex_log(const lmmc_complex_t *z, lmmc_complex_t *out)
复数主值对数: .
lmmc_real_t real
lmmc_status_t lmmc_complex_sqrt(const lmmc_complex_t *z, lmmc_complex_t *out)
采用缩放算法计算复数主值平方根.
lmmc_status_t lmmc_complex_from_polar(lmmc_real_t r, lmmc_real_t theta, lmmc_complex_t *out)
从极坐标构造复数.
lmmc_status_t lmmc_complex_modulus(const lmmc_complex_t *z, lmmc_real_t *out)
采用缩放计算复数模: .
void lmmc_cmat_destroy(lmmc_cmat_t *mat)
销毁复数矩阵,释放其拥有的底层缓冲区.
lmmc_real_t imag
lmmc_status_t lmmc_complex_sub(const lmmc_complex_t *a, const lmmc_complex_t *b, lmmc_complex_t *out)
复数减法: .
void lmmc_cvec_destroy(lmmc_cvec_t *vec)
销毁复数向量,释放其拥有的底层缓冲区.
lmmc_status_t lmmc_complex_div(const lmmc_complex_t *a, const lmmc_complex_t *b, lmmc_complex_t *out)
复数除法: .
复数稠密矩阵(行优先存储).
复数类型,包含实部与虚部.
复数稠密向量.
LMMC binary real type and arithmetic spelling.
#define LMMC_REAL_EXP(res, a)
计算自然指数,*res = exp(*a) 。
#define LMMC_REAL_SIN(res, a)
计算正弦,*res = sin(*a) 。
#define LMMC_REAL_ADD(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_SET(dst, src)
将一个 lmmc_real_t 赋值到另一个:*dst = *src 。
#define LMMC_REAL_MUL(res, a, b)
计算 *res = *a * *b 。
#define LMMC_REAL_COS(res, a)
计算余弦,*res = cos(*a) 。
#define LMMC_REAL_NEG(res, a)
取相反数,*res = -*a 。
#define LMMC_REAL_ATAN2(res, y, x)
计算反正切2,*res = atan2(*y, *x) 。
LMMC 内部使用的公共工具(仅源文件可见).
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