58#ifndef DYNAMIC_COMPLEX_H
59#define DYNAMIC_COMPLEX_H
72#define DC_MALLOC malloc
81#define DC_ASSERT assert
85#ifndef DC_ATOMIC_REFCOUNT
86#define DC_ATOMIC_REFCOUNT 0
89#if DC_ATOMIC_REFCOUNT && __STDC_VERSION__ < 201112L
90 #error "DC_ATOMIC_REFCOUNT requires C11 or later for atomic support (compile with -std=c11 or later)"
94 #include <stdatomic.h>
95 #define DC_ATOMIC_SIZE_T _Atomic size_t
96 #define DC_ATOMIC_FETCH_ADD(ptr, val) atomic_fetch_add(ptr, val)
97 #define DC_ATOMIC_FETCH_SUB(ptr, val) atomic_fetch_sub(ptr, val)
98 #define DC_ATOMIC_LOAD(ptr) atomic_load(ptr)
99 #define DC_ATOMIC_STORE(ptr, val) atomic_store(ptr, val)
101 #define DC_ATOMIC_SIZE_T size_t
102 #define DC_ATOMIC_FETCH_ADD(ptr, val) (*(ptr) += (val), *(ptr) - (val))
103 #define DC_ATOMIC_FETCH_SUB(ptr, val) (*(ptr) -= (val), *(ptr) + (val))
104 #define DC_ATOMIC_LOAD(ptr) (*(ptr))
105 #define DC_ATOMIC_STORE(ptr, val) (*(ptr) = (val))
118#include "dynamic_int.h"
119#include "dynamic_fraction.h"
148 DC_ATOMIC_SIZE_T ref_count;
158 DC_ATOMIC_SIZE_T ref_count;
168 DC_ATOMIC_SIZE_T ref_count;
169 double complex value;
409 int64_t imag_num, int64_t imag_den);
1051#ifdef DC_IMPLEMENTATION
1078 DC_ASSERT(result &&
"dc_int_from_ints: allocation failed");
1080 DC_ATOMIC_STORE(&result->ref_count, 1);
1081 result->real = di_from_int64(real);
1082 result->imag = di_from_int64(imag);
1088 DC_ASSERT(real &&
"dc_int_from_di: real part cannot be NULL");
1089 DC_ASSERT(imag &&
"dc_int_from_di: imaginary part cannot be NULL");
1092 DC_ASSERT(result &&
"dc_int_from_di: allocation failed");
1094 DC_ATOMIC_STORE(&result->ref_count, 1);
1095 result->real = di_retain(real);
1096 result->imag = di_retain(imag);
1102 if (!dc_int_zero_singleton) {
1104 DC_ATOMIC_STORE(&dc_int_zero_singleton->ref_count, SIZE_MAX/2);
1110 if (!dc_int_one_singleton) {
1112 DC_ATOMIC_STORE(&dc_int_one_singleton->ref_count, SIZE_MAX/2);
1118 if (!dc_int_i_singleton) {
1120 DC_ATOMIC_STORE(&dc_int_i_singleton->ref_count, SIZE_MAX/2);
1126 if (!dc_int_neg_one_singleton) {
1128 DC_ATOMIC_STORE(&dc_int_neg_one_singleton->ref_count, SIZE_MAX/2);
1134 if (!dc_int_neg_i_singleton) {
1136 DC_ATOMIC_STORE(&dc_int_neg_i_singleton->ref_count, SIZE_MAX/2);
1142 DC_ASSERT(c &&
"dc_int_retain: cannot retain NULL");
1143 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1148 if (!c || !*c)
return;
1150 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1151 if (old_count == 1) {
1153 if (*c == dc_int_zero_singleton || *c == dc_int_one_singleton ||
1154 *c == dc_int_i_singleton || *c == dc_int_neg_one_singleton ||
1155 *c == dc_int_neg_i_singleton) {
1160 di_release(&(*c)->real);
1161 di_release(&(*c)->imag);
1168 DC_ASSERT(c &&
"dc_int_copy: cannot copy NULL");
1173 DC_ASSERT(a &&
"dc_int_add: first operand cannot be NULL");
1174 DC_ASSERT(b &&
"dc_int_add: second operand cannot be NULL");
1176 di_int real = di_add(a->real, b->real);
1177 di_int imag = di_add(a->imag, b->imag);
1186 DC_ASSERT(a &&
"dc_int_sub: first operand cannot be NULL");
1187 DC_ASSERT(b &&
"dc_int_sub: second operand cannot be NULL");
1189 di_int real = di_sub(a->real, b->real);
1190 di_int imag = di_sub(a->imag, b->imag);
1199 DC_ASSERT(a &&
"dc_int_mul: first operand cannot be NULL");
1200 DC_ASSERT(b &&
"dc_int_mul: second operand cannot be NULL");
1203 di_int ac = di_mul(a->real, b->real);
1204 di_int bd = di_mul(a->imag, b->imag);
1205 di_int ad = di_mul(a->real, b->imag);
1206 di_int bc = di_mul(a->imag, b->real);
1208 di_int real = di_sub(ac, bd);
1209 di_int imag = di_add(ad, bc);
1224 DC_ASSERT(a &&
"dc_int_div: first operand cannot be NULL");
1225 DC_ASSERT(b &&
"dc_int_div: second operand cannot be NULL");
1239 DC_ASSERT(c &&
"dc_int_negate: operand cannot be NULL");
1241 di_int real = di_negate(c->real);
1242 di_int imag = di_negate(c->imag);
1251 DC_ASSERT(c &&
"dc_int_conj: operand cannot be NULL");
1253 di_int real = di_retain(c->real);
1254 di_int imag = di_negate(c->imag);
1263 DC_ASSERT(c &&
"dc_int_real: operand cannot be NULL");
1264 return di_retain(c->real);
1268 DC_ASSERT(c &&
"dc_int_imag: operand cannot be NULL");
1269 return di_retain(c->imag);
1273 DC_ASSERT(a &&
"dc_int_eq: first operand cannot be NULL");
1274 DC_ASSERT(b &&
"dc_int_eq: second operand cannot be NULL");
1276 return di_compare(a->real, b->real) == 0 && di_compare(a->imag, b->imag) == 0;
1280 DC_ASSERT(c &&
"dc_int_is_zero: operand cannot be NULL");
1281 return di_is_zero(c->real) && di_is_zero(c->imag);
1285 DC_ASSERT(c &&
"dc_int_is_real: operand cannot be NULL");
1286 return di_is_zero(c->imag);
1290 DC_ASSERT(c &&
"dc_int_is_imag: operand cannot be NULL");
1291 return di_is_zero(c->real);
1295 DC_ASSERT(c &&
"dc_int_to_string: operand cannot be NULL");
1297 char* real_str = di_to_string(c->real, 10);
1298 char* imag_str = di_to_string(c->imag, 10);
1300 size_t len = strlen(real_str) + strlen(imag_str) + 10;
1301 char* result = DC_MALLOC(len);
1302 DC_ASSERT(result &&
"dc_int_to_string: allocation failed");
1304 bool real_zero = di_is_zero(c->real);
1305 bool imag_zero = di_is_zero(c->imag);
1306 bool imag_neg = di_is_negative(c->imag);
1308 if (real_zero && imag_zero) {
1309 strcpy(result,
"0");
1310 }
else if (imag_zero) {
1311 strcpy(result, real_str);
1312 }
else if (real_zero) {
1313 if (strcmp(imag_str,
"1") == 0) {
1314 strcpy(result,
"i");
1315 }
else if (strcmp(imag_str,
"-1") == 0) {
1316 strcpy(result,
"-i");
1318 sprintf(result,
"%si", imag_str);
1321 if (strcmp(imag_str,
"1") == 0) {
1322 sprintf(result,
"%s+i", real_str);
1323 }
else if (strcmp(imag_str,
"-1") == 0) {
1324 sprintf(result,
"%s-i", real_str);
1325 }
else if (imag_neg) {
1326 sprintf(result,
"%s%si", real_str, imag_str);
1328 sprintf(result,
"%s+%si", real_str, imag_str);
1343 int64_t imag_num, int64_t imag_den) {
1344 df_frac real = df_from_ints(real_num, real_den);
1345 df_frac imag = df_from_ints(imag_num, imag_den);
1353 DC_ASSERT(real &&
"dc_frac_from_df: real part cannot be NULL");
1354 DC_ASSERT(imag &&
"dc_frac_from_df: imaginary part cannot be NULL");
1357 DC_ASSERT(result &&
"dc_frac_from_df: allocation failed");
1359 DC_ATOMIC_STORE(&result->ref_count, 1);
1360 result->real = df_retain(real);
1361 result->imag = df_retain(imag);
1367 if (!dc_frac_zero_singleton) {
1369 DC_ATOMIC_STORE(&dc_frac_zero_singleton->ref_count, SIZE_MAX/2);
1375 if (!dc_frac_one_singleton) {
1377 DC_ATOMIC_STORE(&dc_frac_one_singleton->ref_count, SIZE_MAX/2);
1383 if (!dc_frac_i_singleton) {
1385 DC_ATOMIC_STORE(&dc_frac_i_singleton->ref_count, SIZE_MAX/2);
1391 if (!dc_frac_neg_one_singleton) {
1393 DC_ATOMIC_STORE(&dc_frac_neg_one_singleton->ref_count, SIZE_MAX/2);
1399 if (!dc_frac_neg_i_singleton) {
1401 DC_ATOMIC_STORE(&dc_frac_neg_i_singleton->ref_count, SIZE_MAX/2);
1407 DC_ASSERT(c &&
"dc_frac_retain: cannot retain NULL");
1408 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1413 if (!c || !*c)
return;
1415 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1416 if (old_count == 1) {
1418 if (*c == dc_frac_zero_singleton || *c == dc_frac_one_singleton ||
1419 *c == dc_frac_i_singleton || *c == dc_frac_neg_one_singleton ||
1420 *c == dc_frac_neg_i_singleton) {
1425 df_release(&(*c)->real);
1426 df_release(&(*c)->imag);
1433 DC_ASSERT(c &&
"dc_frac_copy: cannot copy NULL");
1438 DC_ASSERT(a &&
"dc_frac_add: first operand cannot be NULL");
1439 DC_ASSERT(b &&
"dc_frac_add: second operand cannot be NULL");
1441 df_frac real = df_add(a->real, b->real);
1442 df_frac imag = df_add(a->imag, b->imag);
1451 DC_ASSERT(a &&
"dc_frac_sub: first operand cannot be NULL");
1452 DC_ASSERT(b &&
"dc_frac_sub: second operand cannot be NULL");
1454 df_frac real = df_sub(a->real, b->real);
1455 df_frac imag = df_sub(a->imag, b->imag);
1464 DC_ASSERT(a &&
"dc_frac_mul: first operand cannot be NULL");
1465 DC_ASSERT(b &&
"dc_frac_mul: second operand cannot be NULL");
1468 df_frac ac = df_mul(a->real, b->real);
1469 df_frac bd = df_mul(a->imag, b->imag);
1470 df_frac ad = df_mul(a->real, b->imag);
1471 df_frac bc = df_mul(a->imag, b->real);
1473 df_frac real = df_sub(ac, bd);
1474 df_frac imag = df_add(ad, bc);
1489 DC_ASSERT(a &&
"dc_frac_div: first operand cannot be NULL");
1490 DC_ASSERT(b &&
"dc_frac_div: second operand cannot be NULL");
1494 df_frac c2 = df_mul(b->real, b->real);
1495 df_frac d2 = df_mul(b->imag, b->imag);
1496 df_frac denom = df_add(c2, d2);
1498 df_frac ac = df_mul(a->real, b->real);
1499 df_frac bd = df_mul(a->imag, b->imag);
1500 df_frac bc = df_mul(a->imag, b->real);
1501 df_frac ad = df_mul(a->real, b->imag);
1503 df_frac real_num = df_add(ac, bd);
1504 df_frac imag_num = df_sub(bc, ad);
1506 df_frac real = df_div(real_num, denom);
1507 df_frac imag = df_div(imag_num, denom);
1518 df_release(&real_num);
1519 df_release(&imag_num);
1527 DC_ASSERT(c &&
"dc_frac_negate: operand cannot be NULL");
1529 df_frac real = df_negate(c->real);
1530 df_frac imag = df_negate(c->imag);
1539 DC_ASSERT(c &&
"dc_frac_conj: operand cannot be NULL");
1541 df_frac real = df_retain(c->real);
1542 df_frac imag = df_negate(c->imag);
1551 DC_ASSERT(c &&
"dc_frac_reciprocal: operand cannot be NULL");
1552 DC_ASSERT(!
dc_frac_is_zero(c) &&
"dc_frac_reciprocal: division by zero");
1554 df_frac one = df_one();
1555 df_frac zero = df_zero();
1567 DC_ASSERT(c &&
"dc_frac_real: operand cannot be NULL");
1568 return df_retain(c->real);
1572 DC_ASSERT(c &&
"dc_frac_imag: operand cannot be NULL");
1573 return df_retain(c->imag);
1577 DC_ASSERT(a &&
"dc_frac_eq: first operand cannot be NULL");
1578 DC_ASSERT(b &&
"dc_frac_eq: second operand cannot be NULL");
1580 return df_eq(a->real, b->real) && df_eq(a->imag, b->imag);
1584 DC_ASSERT(c &&
"dc_frac_is_zero: operand cannot be NULL");
1585 return df_is_zero(c->real) && df_is_zero(c->imag);
1589 DC_ASSERT(c &&
"dc_frac_is_real: operand cannot be NULL");
1590 return df_is_zero(c->imag);
1594 DC_ASSERT(c &&
"dc_frac_is_imag: operand cannot be NULL");
1595 return df_is_zero(c->real);
1599 DC_ASSERT(c &&
"dc_frac_is_gaussian_int: operand cannot be NULL");
1600 return df_is_integer(c->real) && df_is_integer(c->imag);
1604 DC_ASSERT(c &&
"dc_frac_to_string: operand cannot be NULL");
1606 char* real_str = df_to_string(c->real);
1607 char* imag_str = df_to_string(c->imag);
1609 size_t len = strlen(real_str) + strlen(imag_str) + 10;
1610 char* result = DC_MALLOC(len);
1611 DC_ASSERT(result &&
"dc_frac_to_string: allocation failed");
1613 bool real_zero = df_is_zero(c->real);
1614 bool imag_zero = df_is_zero(c->imag);
1615 bool imag_neg = df_is_negative(c->imag);
1617 if (real_zero && imag_zero) {
1618 strcpy(result,
"0");
1619 }
else if (imag_zero) {
1620 strcpy(result, real_str);
1621 }
else if (real_zero) {
1622 df_frac one = df_one();
1623 df_frac neg_one = df_neg_one();
1624 if (df_cmp(c->imag, one) == 0) {
1625 strcpy(result,
"i");
1626 }
else if (df_cmp(c->imag, neg_one) == 0) {
1627 strcpy(result,
"-i");
1629 sprintf(result,
"%si", imag_str);
1632 df_release(&neg_one);
1634 df_frac one = df_one();
1635 df_frac neg_one = df_neg_one();
1636 if (df_cmp(c->imag, one) == 0) {
1637 sprintf(result,
"%s+i", real_str);
1638 }
else if (df_cmp(c->imag, neg_one) == 0) {
1639 sprintf(result,
"%s-i", real_str);
1640 }
else if (imag_neg) {
1641 sprintf(result,
"%s%si", real_str, imag_str);
1643 sprintf(result,
"%s+%si", real_str, imag_str);
1646 df_release(&neg_one);
1661 DC_ASSERT(result &&
"dc_double_from_doubles: allocation failed");
1663 DC_ATOMIC_STORE(&result->ref_count, 1);
1664 result->value = real + imag * I;
1671 DC_ASSERT(result &&
"dc_double_from_polar: allocation failed");
1673 DC_ATOMIC_STORE(&result->ref_count, 1);
1674 result->value = magnitude * cexp(I * angle);
1680 if (!dc_double_zero_singleton) {
1682 DC_ATOMIC_STORE(&dc_double_zero_singleton->ref_count, SIZE_MAX/2);
1688 if (!dc_double_one_singleton) {
1690 DC_ATOMIC_STORE(&dc_double_one_singleton->ref_count, SIZE_MAX/2);
1696 if (!dc_double_i_singleton) {
1698 DC_ATOMIC_STORE(&dc_double_i_singleton->ref_count, SIZE_MAX/2);
1704 if (!dc_double_neg_one_singleton) {
1706 DC_ATOMIC_STORE(&dc_double_neg_one_singleton->ref_count, SIZE_MAX/2);
1712 if (!dc_double_neg_i_singleton) {
1714 DC_ATOMIC_STORE(&dc_double_neg_i_singleton->ref_count, SIZE_MAX/2);
1720 DC_ASSERT(c &&
"dc_double_retain: cannot retain NULL");
1721 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1726 if (!c || !*c)
return;
1728 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1729 if (old_count == 1) {
1731 if (*c == dc_double_zero_singleton || *c == dc_double_one_singleton ||
1732 *c == dc_double_i_singleton || *c == dc_double_neg_one_singleton ||
1733 *c == dc_double_neg_i_singleton) {
1744 DC_ASSERT(c &&
"dc_double_copy: cannot copy NULL");
1749 DC_ASSERT(a &&
"dc_double_add: first operand cannot be NULL");
1750 DC_ASSERT(b &&
"dc_double_add: second operand cannot be NULL");
1753 DC_ASSERT(result &&
"dc_double_add: allocation failed");
1755 DC_ATOMIC_STORE(&result->ref_count, 1);
1756 result->value = a->value + b->value;
1762 DC_ASSERT(a &&
"dc_double_sub: first operand cannot be NULL");
1763 DC_ASSERT(b &&
"dc_double_sub: second operand cannot be NULL");
1766 DC_ASSERT(result &&
"dc_double_sub: allocation failed");
1768 DC_ATOMIC_STORE(&result->ref_count, 1);
1769 result->value = a->value - b->value;
1775 DC_ASSERT(a &&
"dc_double_mul: first operand cannot be NULL");
1776 DC_ASSERT(b &&
"dc_double_mul: second operand cannot be NULL");
1779 DC_ASSERT(result &&
"dc_double_mul: allocation failed");
1781 DC_ATOMIC_STORE(&result->ref_count, 1);
1782 result->value = a->value * b->value;
1788 DC_ASSERT(a &&
"dc_double_div: first operand cannot be NULL");
1789 DC_ASSERT(b &&
"dc_double_div: second operand cannot be NULL");
1793 DC_ASSERT(result &&
"dc_double_div: allocation failed");
1795 DC_ATOMIC_STORE(&result->ref_count, 1);
1796 result->value = a->value / b->value;
1802 DC_ASSERT(c &&
"dc_double_negate: operand cannot be NULL");
1805 DC_ASSERT(result &&
"dc_double_negate: allocation failed");
1807 DC_ATOMIC_STORE(&result->ref_count, 1);
1808 result->value = -c->value;
1814 DC_ASSERT(c &&
"dc_double_conj: operand cannot be NULL");
1817 DC_ASSERT(result &&
"dc_double_conj: allocation failed");
1819 DC_ATOMIC_STORE(&result->ref_count, 1);
1820 result->value = conj(c->value);
1826 DC_ASSERT(c &&
"dc_double_exp: operand cannot be NULL");
1829 DC_ASSERT(result &&
"dc_double_exp: allocation failed");
1831 DC_ATOMIC_STORE(&result->ref_count, 1);
1832 result->value = cexp(c->value);
1838 DC_ASSERT(c &&
"dc_double_log: operand cannot be NULL");
1842 DC_ASSERT(result &&
"dc_double_log: allocation failed");
1844 DC_ATOMIC_STORE(&result->ref_count, 1);
1845 result->value = clog(c->value);
1851 DC_ASSERT(a &&
"dc_double_pow: base cannot be NULL");
1852 DC_ASSERT(b &&
"dc_double_pow: exponent cannot be NULL");
1855 DC_ASSERT(result &&
"dc_double_pow: allocation failed");
1857 DC_ATOMIC_STORE(&result->ref_count, 1);
1858 result->value = cpow(a->value, b->value);
1864 DC_ASSERT(c &&
"dc_double_sqrt: operand cannot be NULL");
1867 DC_ASSERT(result &&
"dc_double_sqrt: allocation failed");
1869 DC_ATOMIC_STORE(&result->ref_count, 1);
1870 result->value = csqrt(c->value);
1876 DC_ASSERT(c &&
"dc_double_sin: operand cannot be NULL");
1879 DC_ASSERT(result &&
"dc_double_sin: allocation failed");
1881 DC_ATOMIC_STORE(&result->ref_count, 1);
1882 result->value = csin(c->value);
1888 DC_ASSERT(c &&
"dc_double_cos: operand cannot be NULL");
1891 DC_ASSERT(result &&
"dc_double_cos: allocation failed");
1893 DC_ATOMIC_STORE(&result->ref_count, 1);
1894 result->value = ccos(c->value);
1900 DC_ASSERT(c &&
"dc_double_tan: operand cannot be NULL");
1903 DC_ASSERT(result &&
"dc_double_tan: allocation failed");
1905 DC_ATOMIC_STORE(&result->ref_count, 1);
1906 result->value = ctan(c->value);
1912 DC_ASSERT(c &&
"dc_double_sinh: operand cannot be NULL");
1915 DC_ASSERT(result &&
"dc_double_sinh: allocation failed");
1917 DC_ATOMIC_STORE(&result->ref_count, 1);
1918 result->value = csinh(c->value);
1924 DC_ASSERT(c &&
"dc_double_cosh: operand cannot be NULL");
1927 DC_ASSERT(result &&
"dc_double_cosh: allocation failed");
1929 DC_ATOMIC_STORE(&result->ref_count, 1);
1930 result->value = ccosh(c->value);
1936 DC_ASSERT(c &&
"dc_double_tanh: operand cannot be NULL");
1939 DC_ASSERT(result &&
"dc_double_tanh: allocation failed");
1941 DC_ATOMIC_STORE(&result->ref_count, 1);
1942 result->value = ctanh(c->value);
1948 DC_ASSERT(c &&
"dc_double_real: operand cannot be NULL");
1949 return creal(c->value);
1953 DC_ASSERT(c &&
"dc_double_imag: operand cannot be NULL");
1954 return cimag(c->value);
1958 DC_ASSERT(c &&
"dc_double_abs: operand cannot be NULL");
1959 return cabs(c->value);
1963 DC_ASSERT(c &&
"dc_double_arg: operand cannot be NULL");
1964 return carg(c->value);
1968 DC_ASSERT(a &&
"dc_double_eq: first operand cannot be NULL");
1969 DC_ASSERT(b &&
"dc_double_eq: second operand cannot be NULL");
1971 return creal(a->value) == creal(b->value) && cimag(a->value) == cimag(b->value);
1975 DC_ASSERT(c &&
"dc_double_is_zero: operand cannot be NULL");
1976 return creal(c->value) == 0.0 && cimag(c->value) == 0.0;
1980 DC_ASSERT(c &&
"dc_double_is_real: operand cannot be NULL");
1981 return cimag(c->value) == 0.0;
1985 DC_ASSERT(c &&
"dc_double_is_imag: operand cannot be NULL");
1986 return creal(c->value) == 0.0;
1990 DC_ASSERT(c &&
"dc_double_is_nan: operand cannot be NULL");
1991 return isnan(creal(c->value)) || isnan(cimag(c->value));
1995 DC_ASSERT(c &&
"dc_double_is_inf: operand cannot be NULL");
1996 return isinf(creal(c->value)) || isinf(cimag(c->value));
2000 DC_ASSERT(c &&
"dc_double_to_string: operand cannot be NULL");
2002 char* result = DC_MALLOC(256);
2003 DC_ASSERT(result &&
"dc_double_to_string: allocation failed");
2005 double real = creal(c->value);
2006 double imag = cimag(c->value);
2008 if (real == 0.0 && imag == 0.0) {
2009 strcpy(result,
"0");
2010 }
else if (imag == 0.0) {
2011 sprintf(result,
"%g", real);
2012 }
else if (real == 0.0) {
2014 strcpy(result,
"i");
2015 }
else if (imag == -1.0) {
2016 strcpy(result,
"-i");
2018 sprintf(result,
"%gi", imag);
2022 sprintf(result,
"%g+i", real);
2023 }
else if (imag == -1.0) {
2024 sprintf(result,
"%g-i", real);
2025 }
else if (imag < 0) {
2026 sprintf(result,
"%g%gi", real, imag);
2028 sprintf(result,
"%g+%gi", real, imag);
2040 DC_ASSERT(c &&
"dc_int_to_frac: operand cannot be NULL");
2042 df_frac real = df_from_di(c->real, di_one());
2043 df_frac imag = df_from_di(c->imag, di_one());
2053 DC_ASSERT(c &&
"dc_int_to_double: operand cannot be NULL");
2055 double real = di_to_double(c->real);
2056 double imag = di_to_double(c->imag);
2062 DC_ASSERT(c &&
"dc_frac_to_double: operand cannot be NULL");
2064 double real = df_to_double(c->real);
2065 double imag = df_to_double(c->imag);
2071 DC_ASSERT(c &&
"dc_frac_to_int: operand cannot be NULL");
2074 double real = df_to_double(c->real);
2075 double imag = df_to_double(c->imag);
2077 int64_t real_rounded = (int64_t)round(real);
2078 int64_t imag_rounded = (int64_t)round(imag);
2084 DC_ASSERT(c &&
"dc_double_to_int: operand cannot be NULL");
2086 double real = creal(c->value);
2087 double imag = cimag(c->value);
2089 int64_t real_rounded = (int64_t)round(real);
2090 int64_t imag_rounded = (int64_t)round(imag);
2096 DC_ASSERT(c &&
"dc_double_to_frac: operand cannot be NULL");
2097 DC_ASSERT(max_denominator > 0 &&
"dc_double_to_frac: max_denominator must be positive");
2099 double real = creal(c->value);
2100 double imag = cimag(c->value);
2102 df_frac real_frac = df_from_double(real, max_denominator);
2103 df_frac imag_frac = df_from_double(imag, max_denominator);
2107 df_release(&real_frac);
2108 df_release(&imag_frac);
struct dc_complex_double_internal * dc_complex_double
Opaque pointer to a floating-point complex number.
struct dc_complex_frac_internal * dc_complex_frac
Opaque pointer to a rational complex number.
struct dc_complex_int_internal * dc_complex_int
Opaque pointer to a Gaussian integer (complex number with integer components)
dc_complex_double dc_int_to_double(dc_complex_int c)
Convert Gaussian integer to floating-point complex (lossless for small integers)
dc_complex_double dc_frac_to_double(dc_complex_frac c)
Convert rational complex to floating-point complex.
dc_complex_int dc_frac_to_int(dc_complex_frac c)
Convert rational complex to Gaussian integer (with rounding)
dc_complex_frac dc_int_to_frac(dc_complex_int c)
Convert Gaussian integer to rational complex (lossless)
dc_complex_int dc_double_to_int(dc_complex_double c)
Convert floating-point complex to Gaussian integer (with rounding)
dc_complex_frac dc_double_to_frac(dc_complex_double c, int64_t max_denominator)
Convert floating-point complex to rational complex (with approximation)
bool dc_double_is_imag(dc_complex_double c)
Test if a floating-point complex number is purely imaginary (real part is zero)
dc_complex_double dc_double_pow(dc_complex_double a, dc_complex_double b)
Complex power function.
dc_complex_double dc_double_tan(dc_complex_double c)
Complex tangent function.
double dc_double_abs(dc_complex_double c)
Get the absolute value (magnitude) of a complex number.
dc_complex_double dc_double_sin(dc_complex_double c)
Complex sine function.
dc_complex_double dc_double_exp(dc_complex_double c)
Complex exponential function.
dc_complex_double dc_double_sinh(dc_complex_double c)
Complex hyperbolic sine function.
bool dc_double_is_inf(dc_complex_double c)
Test if a floating-point complex number contains infinity.
dc_complex_double dc_double_cos(dc_complex_double c)
Complex cosine function.
dc_complex_double dc_double_div(dc_complex_double a, dc_complex_double b)
Divide two floating-point complex numbers.
dc_complex_double dc_double_retain(dc_complex_double c)
Increment reference count and return the same object.
dc_complex_double dc_double_one(void)
Get the floating-point complex one (1.0 + 0.0i)
dc_complex_double dc_double_copy(dc_complex_double c)
Create a new copy with reference count 1.
double dc_double_arg(dc_complex_double c)
Get the argument (phase angle) of a complex number.
dc_complex_double dc_double_negate(dc_complex_double c)
Negate a floating-point complex number.
dc_complex_double dc_double_add(dc_complex_double a, dc_complex_double b)
Add two floating-point complex numbers.
dc_complex_double dc_double_log(dc_complex_double c)
Complex natural logarithm.
dc_complex_double dc_double_from_doubles(double real, double imag)
Create a floating-point complex number from real and imaginary parts.
dc_complex_double dc_double_neg_one(void)
Get the floating-point complex -1 (-1.0 + 0.0i)
dc_complex_double dc_double_conj(dc_complex_double c)
Complex conjugate of a floating-point complex number.
bool dc_double_is_real(dc_complex_double c)
Test if a floating-point complex number is real (imaginary part is zero)
dc_complex_double dc_double_sqrt(dc_complex_double c)
Complex square root.
dc_complex_double dc_double_cosh(dc_complex_double c)
Complex hyperbolic cosine function.
bool dc_double_is_zero(dc_complex_double c)
Test if a floating-point complex number is zero.
dc_complex_double dc_double_neg_i(void)
Get the floating-point complex -i (0.0 + -1.0i)
dc_complex_double dc_double_zero(void)
Get the floating-point complex zero (0.0 + 0.0i)
double dc_double_imag(dc_complex_double c)
Get the imaginary part of a floating-point complex number.
char * dc_double_to_string(dc_complex_double c)
Convert floating-point complex number to mathematical string representation.
dc_complex_double dc_double_mul(dc_complex_double a, dc_complex_double b)
Multiply two floating-point complex numbers.
double dc_double_real(dc_complex_double c)
Get the real part of a floating-point complex number.
dc_complex_double dc_double_tanh(dc_complex_double c)
Complex hyperbolic tangent function.
dc_complex_double dc_double_from_polar(double magnitude, double angle)
Create a floating-point complex number from polar coordinates.
bool dc_double_is_nan(dc_complex_double c)
Test if a floating-point complex number contains NaN.
void dc_double_release(dc_complex_double *c)
Decrement reference count and possibly free memory.
dc_complex_double dc_double_sub(dc_complex_double a, dc_complex_double b)
Subtract two floating-point complex numbers.
bool dc_double_eq(dc_complex_double a, dc_complex_double b)
Test if two floating-point complex numbers are equal.
dc_complex_double dc_double_i(void)
Get the floating-point complex i (0.0 + 1.0i)
df_frac dc_frac_imag(dc_complex_frac c)
Get the imaginary part of a rational complex number.
dc_complex_frac dc_frac_i(void)
Get the rational complex i (0/1 + 1/1 i)
dc_complex_frac dc_frac_add(dc_complex_frac a, dc_complex_frac b)
Add two rational complex numbers.
dc_complex_frac dc_frac_sub(dc_complex_frac a, dc_complex_frac b)
Subtract two rational complex numbers.
dc_complex_frac dc_frac_mul(dc_complex_frac a, dc_complex_frac b)
Multiply two rational complex numbers.
char * dc_frac_to_string(dc_complex_frac c)
Convert rational complex number to mathematical string representation.
bool dc_frac_is_gaussian_int(dc_complex_frac c)
Test if a rational complex number is actually a Gaussian integer.
dc_complex_frac dc_frac_retain(dc_complex_frac c)
Increment reference count and return the same object.
bool dc_frac_is_imag(dc_complex_frac c)
Test if a rational complex number is purely imaginary (real part is zero)
dc_complex_frac dc_frac_copy(dc_complex_frac c)
Create a new copy with reference count 1.
df_frac dc_frac_real(dc_complex_frac c)
Get the real part of a rational complex number.
dc_complex_frac dc_frac_zero(void)
Get the rational complex zero (0/1 + 0/1 i)
dc_complex_frac dc_frac_one(void)
Get the rational complex one (1/1 + 0/1 i)
bool dc_frac_is_real(dc_complex_frac c)
Test if a rational complex number is real (imaginary part is zero)
dc_complex_frac dc_frac_from_df(df_frac real, df_frac imag)
Create a rational complex number from fraction components.
dc_complex_frac dc_frac_conj(dc_complex_frac c)
Complex conjugate of a rational complex number.
dc_complex_frac dc_frac_negate(dc_complex_frac c)
Negate a rational complex number.
dc_complex_frac dc_frac_reciprocal(dc_complex_frac c)
Reciprocal of a rational complex number.
dc_complex_frac dc_frac_div(dc_complex_frac a, dc_complex_frac b)
Divide two rational complex numbers.
bool dc_frac_is_zero(dc_complex_frac c)
Test if a rational complex number is zero.
void dc_frac_release(dc_complex_frac *c)
Decrement reference count and possibly free memory.
bool dc_frac_eq(dc_complex_frac a, dc_complex_frac b)
Test if two rational complex numbers are equal.
dc_complex_frac dc_frac_from_ints(int64_t real_num, int64_t real_den, int64_t imag_num, int64_t imag_den)
Create a rational complex number from integer components.
dc_complex_frac dc_frac_neg_i(void)
Get the rational complex -i (0/1 + -1/1 i)
dc_complex_frac dc_frac_neg_one(void)
Get the rational complex -1 (-1/1 + 0/1 i)
dc_complex_int dc_int_one(void)
Get the Gaussian integer one (1 + 0i)
dc_complex_int dc_int_negate(dc_complex_int c)
Negate a Gaussian integer.
di_int dc_int_imag(dc_complex_int c)
Get the imaginary part of a Gaussian integer.
dc_complex_int dc_int_from_ints(int64_t real, int64_t imag)
Create a Gaussian integer from int64_t real and imaginary parts.
dc_complex_int dc_int_add(dc_complex_int a, dc_complex_int b)
Add two Gaussian integers.
dc_complex_int dc_int_from_di(di_int real, di_int imag)
Create a Gaussian integer from dynamic integer components.
bool dc_int_is_imag(dc_complex_int c)
Test if a Gaussian integer is purely imaginary (real part is zero)
bool dc_int_is_zero(dc_complex_int c)
Test if a Gaussian integer is zero.
dc_complex_int dc_int_conj(dc_complex_int c)
Complex conjugate of a Gaussian integer.
dc_complex_int dc_int_i(void)
Get the Gaussian integer i (0 + 1i)
dc_complex_int dc_int_neg_one(void)
Get the Gaussian integer -1 (-1 + 0i)
bool dc_int_eq(dc_complex_int a, dc_complex_int b)
Test if two Gaussian integers are equal.
dc_complex_int dc_int_mul(dc_complex_int a, dc_complex_int b)
Multiply two Gaussian integers.
dc_complex_frac dc_int_div(dc_complex_int a, dc_complex_int b)
Divide two Gaussian integers (returns exact rational result)
dc_complex_int dc_int_sub(dc_complex_int a, dc_complex_int b)
Subtract two Gaussian integers.
bool dc_int_is_real(dc_complex_int c)
Test if a Gaussian integer is real (imaginary part is zero)
dc_complex_int dc_int_neg_i(void)
Get the Gaussian integer -i (0 - 1i)
dc_complex_int dc_int_copy(dc_complex_int c)
Create a new copy with reference count 1.
dc_complex_int dc_int_retain(dc_complex_int c)
Increment reference count and return the same object.
void dc_int_release(dc_complex_int *c)
Decrement reference count and possibly free memory.
char * dc_int_to_string(dc_complex_int c)
Convert Gaussian integer to mathematical string representation.
di_int dc_int_real(dc_complex_int c)
Get the real part of a Gaussian integer.
dc_complex_int dc_int_zero(void)
Get the Gaussian integer zero (0 + 0i)
Internal structure for a floating-point complex number.
Internal structure for a rational complex number.
Internal structure for a Gaussian integer.