15 return isfinite(z->
real) && isfinite(z->
imag);
20 return lmmc_complex_is_finite(z)
27 if (out == NULL || !isfinite(real) || !isfinite(imag)) {
39 if (out == NULL || !isfinite(r) || !isfinite(theta) || r < 0.0) {
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)
59 if (a == NULL || b == NULL || out == NULL) {
62 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
67 return lmmc_complex_finite_result(out);
72 if (a == NULL || b == NULL || out == NULL) {
75 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
80 return lmmc_complex_finite_result(out);
91static double lmmc_scaled_sum_products(
double a,
double b,
int ep,
92 double c,
double d,
int eq,
int* scale)
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;
103static int lmmc_products_are_normal(
double p,
double q)
105 return isfinite(p) && isfinite(q) &&
106 fabs(p) >= DBL_MIN && fabs(q) >= DBL_MIN;
123static double lmmc_sum_products(
double a,
double b,
double c,
double d)
125 const double p = a * b;
126 const double q = c * d;
128 double ma, mb, mc, md;
131 if (a == 0.0 || b == 0.0 || c == 0.0 || d == 0.0) {
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) {
144 const double sum = lmmc_scaled_sum_products(ma, mb, ea + eb,
145 mc, md, ec + ed, &scale);
146 return scalbn(sum, scale);
153 if (a == NULL || b == NULL || out == NULL) {
156 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
162 if (!lmmc_complex_is_finite(&result)) {
172 int denominator_scale, real_scale, imag_scale;
175 if (a == NULL || b == NULL || out == NULL) {
178 if (!lmmc_complex_is_finite(a) || !lmmc_complex_is_finite(b)) {
181 if (b->
real == 0.0 && b->
imag == 0.0) {
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)) {
206 if (z == NULL || out == NULL) {
209 if (!lmmc_complex_is_finite(z)) {
214 return lmmc_complex_finite_result(out);
221 if (z == NULL || out == NULL) {
224 if (!lmmc_complex_is_finite(z)) {
228 if (!isfinite(modulus)) {
237 if (z == NULL || out == NULL) {
240 if (!lmmc_complex_is_finite(z)) {
252 if (z == NULL || out == NULL) {
255 if (!lmmc_complex_is_finite(z)) {
263 if (!isfinite(ex) || ex < DBL_MIN) {
265 ex = exp(z->
real * 0.5);
266 result.
real = (ex * cos_y) * ex;
267 result.
imag = (ex * sin_y) * ex;
272 if (!lmmc_complex_is_finite(&result)) {
287 if (z == NULL || out == NULL) {
290 if (!lmmc_complex_is_finite(z)) {
293 if (z->
real == 0.0 && z->
imag == 0.0) {
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));
320 ratio = minor / major;
321 result.
real = log(major) + 0.5 * log1p(ratio * ratio);
324 if (!lmmc_complex_is_finite(&result)) {
338 if (z == NULL || out == NULL) {
341 if (!lmmc_complex_is_finite(z)) {
345 if (z->
imag == 0.0) {
351 result.
imag = copysign(0.0, z->
imag);
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);
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);
370 if (!lmmc_complex_is_finite(&result)) {
386static lmmc_complex_t lmmc_complex_hyperbolic_products(
double even,
double odd,
double y)
388 const double cosh_y = cosh(y);
389 const double sinh_y = sinh(y);
392 if (isfinite(cosh_y) && isfinite(sinh_y)) {
393 result.
real = even * cosh_y;
394 result.
imag = odd * sinh_y;
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;
409 if (z == NULL || out == NULL) {
412 if (!lmmc_complex_is_finite(z)) {
420 result = lmmc_complex_hyperbolic_products(sin_x, cos_x, z->
imag);
421 if (!lmmc_complex_is_finite(&result)) {
433 if (z == NULL || out == NULL) {
436 if (!lmmc_complex_is_finite(z)) {
444 result = lmmc_complex_hyperbolic_products(cos_x, -sin_x, z->
imag);
445 if (!lmmc_complex_is_finite(&result)) {
469 double remaining = fabs(exponent);
472 if (exponent < 0.0) {
478 while (remaining != 0.0) {
479 if (fmod(remaining, 2.0) != 0.0) {
490 remaining = floor(remaining * 0.5);
491 if (remaining != 0.0) {
506 if (exp->
real == 0.0 && exp->
imag == 0.0) {
508 }
else if (exp->
real > 0.0) {
523 if (base == NULL || exp == NULL || out == NULL) {
527 if (!lmmc_complex_is_finite(base) || !lmmc_complex_is_finite(exp)) {
531 if (base->
real == 0.0 && base->
imag == 0.0) {
532 return lmmc_complex_zero_power(exp, out);
535 if (exp->
imag == 0.0 && trunc(exp->
real) == exp->
real) {
536 return lmmc_complex_integer_power(base, exp->
real, out);
563 if (out == NULL || size == 0) {
567 if (!lmmc_safe_mul_size(size,
sizeof(
lmmc_complex_t), &n_bytes)) {
575 memset(data, 0, n_bytes);
585 size_t n_elem, n_bytes;
588 if (out == NULL || rows == 0 || cols == 0) {
592 if (!lmmc_safe_mul_size(rows, cols, &n_elem)) {
595 if (!lmmc_safe_mul_size(n_elem,
sizeof(
lmmc_complex_t), &n_bytes)) {
603 memset(data, 0, n_bytes);
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_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_status_t lmmc_complex_log(const lmmc_complex_t *z, lmmc_complex_t *out)
复数主值对数: .
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_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) 。
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_NUMERICAL_FAILURE
@ LMMC_STATUS_ALLOCATION_FAILED
@ LMMC_STATUS_INVALID_ARGUMENT
@ LMMC_STATUS_OUT_OF_RANGE