Dynamic Complex Library 1.0.0
Reference-counted arbitrary precision complex number library (MIT OR Unlicense)
Loading...
Searching...
No Matches
dynamic_complex.h
Go to the documentation of this file.
1
58#ifndef DYNAMIC_COMPLEX_H
59#define DYNAMIC_COMPLEX_H
60
61#include <stdint.h>
62#include <stddef.h>
63#include <stdbool.h>
64#include <stdlib.h>
65#include <stdio.h>
66#include <string.h>
67#include <math.h>
68#include <complex.h>
69
70/* Configuration macros */
71#ifndef DC_MALLOC
72#define DC_MALLOC malloc
73#endif
74
75#ifndef DC_FREE
76#define DC_FREE free
77#endif
78
79#ifndef DC_ASSERT
80#include <assert.h>
81#define DC_ASSERT assert
82#endif
83
84/* Atomic reference counting configuration */
85#ifndef DC_ATOMIC_REFCOUNT
86#define DC_ATOMIC_REFCOUNT 0
87#endif
88
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)"
91#endif
92
93#if DC_ATOMIC_REFCOUNT
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)
100#else
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))
106#endif
107
108/* API macros */
109#ifdef DC_STATIC
110#define DC_DEC static
111#define DC_DEF static
112#else
113#define DC_DEC extern
114#define DC_DEF /* nothing - default linkage */
115#endif
116
117/* Include dependencies - user must ensure these are available */
118#include "dynamic_int.h"
119#include "dynamic_fraction.h"
120
121// ============================================================================
122// TYPE DEFINITIONS
123// ============================================================================
124
130
136
142
148 DC_ATOMIC_SIZE_T ref_count;
149 di_int real;
150 di_int imag;
151};
152
158 DC_ATOMIC_SIZE_T ref_count;
159 df_frac real;
160 df_frac imag;
161};
162
168 DC_ATOMIC_SIZE_T ref_count;
169 double complex value;
170};
171
172// ============================================================================
173// INTEGER COMPLEX INTERFACE
174// ============================================================================
175
182/* Creation */
183
191DC_DEC dc_complex_int dc_int_from_ints(int64_t real, int64_t imag);
192
201DC_DEC dc_complex_int dc_int_from_di(di_int real, di_int imag);
202
209
216
223
230
237
238/* Memory management */
239
247
256
264
265/* Arithmetic */
266
275
284
294
305
313
322
323/* Accessors */
324
332
340
341/* Comparisons */
342
350
357
364
371
372/* String conversion */
373
382
385// ============================================================================
386// FRACTION COMPLEX INTERFACE
387// ============================================================================
388
395/* Creation */
396
408DC_DEC dc_complex_frac dc_frac_from_ints(int64_t real_num, int64_t real_den,
409 int64_t imag_num, int64_t imag_den);
410
419DC_DEC dc_complex_frac dc_frac_from_df(df_frac real, df_frac imag);
420
427
434
441
448
455
456/* Memory management */
457
465
474
482
483/* Arithmetic */
484
494
504
515
526
534
543
552
553/* Accessors */
554
562
570
571/* Comparisons */
572
581
588
595
602
610
611/* String conversion */
612
622
625// ============================================================================
626// DOUBLE COMPLEX INTERFACE
627// ============================================================================
628
635/* Creation */
636
644DC_DEC dc_complex_double dc_double_from_doubles(double real, double imag);
645
654DC_DEC dc_complex_double dc_double_from_polar(double magnitude, double angle);
655
662
669
676
683
690
691/* Memory management */
692
700
709
717
718/* Arithmetic */
719
729
739
749
759
767
777
778/* Complex-specific operations */
779
788
798
809
819
828
837
846
855
864
873
874/* Accessors */
875
883
891
900
909
910/* Comparisons */
911
921
928
935
942
950
958
959/* String conversion */
960
970
973// ============================================================================
974// TYPE CONVERSION INTERFACE
975// ============================================================================
976
983/* Upward conversions (lossless) */
984
993
1002
1011
1012/* Downward conversions (may round) */
1013
1023
1033
1043DC_DEC dc_complex_frac dc_double_to_frac(dc_complex_double c, int64_t max_denominator);
1044
1047// ============================================================================
1048// IMPLEMENTATION
1049// ============================================================================
1050
1051#ifdef DC_IMPLEMENTATION
1052
1053// Global singletons for common constants
1054static dc_complex_int dc_int_zero_singleton = NULL;
1055static dc_complex_int dc_int_one_singleton = NULL;
1056static dc_complex_int dc_int_i_singleton = NULL;
1057static dc_complex_int dc_int_neg_one_singleton = NULL;
1058static dc_complex_int dc_int_neg_i_singleton = NULL;
1059
1060static dc_complex_frac dc_frac_zero_singleton = NULL;
1061static dc_complex_frac dc_frac_one_singleton = NULL;
1062static dc_complex_frac dc_frac_i_singleton = NULL;
1063static dc_complex_frac dc_frac_neg_one_singleton = NULL;
1064static dc_complex_frac dc_frac_neg_i_singleton = NULL;
1065
1066static dc_complex_double dc_double_zero_singleton = NULL;
1067static dc_complex_double dc_double_one_singleton = NULL;
1068static dc_complex_double dc_double_i_singleton = NULL;
1069static dc_complex_double dc_double_neg_one_singleton = NULL;
1070static dc_complex_double dc_double_neg_i_singleton = NULL;
1071
1072// ============================================================================
1073// INTEGER COMPLEX IMPLEMENTATION
1074// ============================================================================
1075
1076DC_DEF dc_complex_int dc_int_from_ints(int64_t real, int64_t imag) {
1077 dc_complex_int result = DC_MALLOC(sizeof(struct dc_complex_int_internal));
1078 DC_ASSERT(result && "dc_int_from_ints: allocation failed");
1079
1080 DC_ATOMIC_STORE(&result->ref_count, 1);
1081 result->real = di_from_int64(real);
1082 result->imag = di_from_int64(imag);
1083
1084 return result;
1085}
1086
1087DC_DEF dc_complex_int dc_int_from_di(di_int real, di_int 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");
1090
1091 dc_complex_int result = DC_MALLOC(sizeof(struct dc_complex_int_internal));
1092 DC_ASSERT(result && "dc_int_from_di: allocation failed");
1093
1094 DC_ATOMIC_STORE(&result->ref_count, 1);
1095 result->real = di_retain(real);
1096 result->imag = di_retain(imag);
1097
1098 return result;
1099}
1100
1101DC_DEF dc_complex_int dc_int_zero(void) {
1102 if (!dc_int_zero_singleton) {
1103 dc_int_zero_singleton = dc_int_from_ints(0, 0);
1104 DC_ATOMIC_STORE(&dc_int_zero_singleton->ref_count, SIZE_MAX/2);
1105 }
1106 return dc_int_retain(dc_int_zero_singleton);
1107}
1108
1109DC_DEF dc_complex_int dc_int_one(void) {
1110 if (!dc_int_one_singleton) {
1111 dc_int_one_singleton = dc_int_from_ints(1, 0);
1112 DC_ATOMIC_STORE(&dc_int_one_singleton->ref_count, SIZE_MAX/2);
1113 }
1114 return dc_int_retain(dc_int_one_singleton);
1115}
1116
1117DC_DEF dc_complex_int dc_int_i(void) {
1118 if (!dc_int_i_singleton) {
1119 dc_int_i_singleton = dc_int_from_ints(0, 1);
1120 DC_ATOMIC_STORE(&dc_int_i_singleton->ref_count, SIZE_MAX/2);
1121 }
1122 return dc_int_retain(dc_int_i_singleton);
1123}
1124
1125DC_DEF dc_complex_int dc_int_neg_one(void) {
1126 if (!dc_int_neg_one_singleton) {
1127 dc_int_neg_one_singleton = dc_int_from_ints(-1, 0);
1128 DC_ATOMIC_STORE(&dc_int_neg_one_singleton->ref_count, SIZE_MAX/2);
1129 }
1130 return dc_int_retain(dc_int_neg_one_singleton);
1131}
1132
1133DC_DEF dc_complex_int dc_int_neg_i(void) {
1134 if (!dc_int_neg_i_singleton) {
1135 dc_int_neg_i_singleton = dc_int_from_ints(0, -1);
1136 DC_ATOMIC_STORE(&dc_int_neg_i_singleton->ref_count, SIZE_MAX/2);
1137 }
1138 return dc_int_retain(dc_int_neg_i_singleton);
1139}
1140
1142 DC_ASSERT(c && "dc_int_retain: cannot retain NULL");
1143 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1144 return c;
1145}
1146
1147DC_DEF void dc_int_release(dc_complex_int* c) {
1148 if (!c || !*c) return;
1149
1150 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1151 if (old_count == 1) {
1152 // Don't free singletons
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) {
1156 *c = NULL;
1157 return;
1158 }
1159
1160 di_release(&(*c)->real);
1161 di_release(&(*c)->imag);
1162 DC_FREE(*c);
1163 }
1164 *c = NULL;
1165}
1166
1168 DC_ASSERT(c && "dc_int_copy: cannot copy NULL");
1169 return dc_int_from_di(c->real, c->imag);
1170}
1171
1173 DC_ASSERT(a && "dc_int_add: first operand cannot be NULL");
1174 DC_ASSERT(b && "dc_int_add: second operand cannot be NULL");
1175
1176 di_int real = di_add(a->real, b->real);
1177 di_int imag = di_add(a->imag, b->imag);
1178 dc_complex_int result = dc_int_from_di(real, imag);
1179 di_release(&real);
1180 di_release(&imag);
1181
1182 return result;
1183}
1184
1186 DC_ASSERT(a && "dc_int_sub: first operand cannot be NULL");
1187 DC_ASSERT(b && "dc_int_sub: second operand cannot be NULL");
1188
1189 di_int real = di_sub(a->real, b->real);
1190 di_int imag = di_sub(a->imag, b->imag);
1191 dc_complex_int result = dc_int_from_di(real, imag);
1192 di_release(&real);
1193 di_release(&imag);
1194
1195 return result;
1196}
1197
1199 DC_ASSERT(a && "dc_int_mul: first operand cannot be NULL");
1200 DC_ASSERT(b && "dc_int_mul: second operand cannot be NULL");
1201
1202 // (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
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);
1207
1208 di_int real = di_sub(ac, bd);
1209 di_int imag = di_add(ad, bc);
1210
1211 dc_complex_int result = dc_int_from_di(real, imag);
1212
1213 di_release(&ac);
1214 di_release(&bd);
1215 di_release(&ad);
1216 di_release(&bc);
1217 di_release(&real);
1218 di_release(&imag);
1219
1220 return result;
1221}
1222
1224 DC_ASSERT(a && "dc_int_div: first operand cannot be NULL");
1225 DC_ASSERT(b && "dc_int_div: second operand cannot be NULL");
1226
1227 // Convert to fractions and divide
1230 dc_complex_frac result = dc_frac_div(af, bf);
1231
1232 dc_frac_release(&af);
1233 dc_frac_release(&bf);
1234
1235 return result;
1236}
1237
1239 DC_ASSERT(c && "dc_int_negate: operand cannot be NULL");
1240
1241 di_int real = di_negate(c->real);
1242 di_int imag = di_negate(c->imag);
1243 dc_complex_int result = dc_int_from_di(real, imag);
1244 di_release(&real);
1245 di_release(&imag);
1246
1247 return result;
1248}
1249
1251 DC_ASSERT(c && "dc_int_conj: operand cannot be NULL");
1252
1253 di_int real = di_retain(c->real);
1254 di_int imag = di_negate(c->imag);
1255 dc_complex_int result = dc_int_from_di(real, imag);
1256 di_release(&real);
1257 di_release(&imag);
1258
1259 return result;
1260}
1261
1262DC_DEF di_int dc_int_real(dc_complex_int c) {
1263 DC_ASSERT(c && "dc_int_real: operand cannot be NULL");
1264 return di_retain(c->real);
1265}
1266
1267DC_DEF di_int dc_int_imag(dc_complex_int c) {
1268 DC_ASSERT(c && "dc_int_imag: operand cannot be NULL");
1269 return di_retain(c->imag);
1270}
1271
1272DC_DEF bool dc_int_eq(dc_complex_int a, dc_complex_int b) {
1273 DC_ASSERT(a && "dc_int_eq: first operand cannot be NULL");
1274 DC_ASSERT(b && "dc_int_eq: second operand cannot be NULL");
1275
1276 return di_compare(a->real, b->real) == 0 && di_compare(a->imag, b->imag) == 0;
1277}
1278
1279DC_DEF bool dc_int_is_zero(dc_complex_int c) {
1280 DC_ASSERT(c && "dc_int_is_zero: operand cannot be NULL");
1281 return di_is_zero(c->real) && di_is_zero(c->imag);
1282}
1283
1284DC_DEF bool dc_int_is_real(dc_complex_int c) {
1285 DC_ASSERT(c && "dc_int_is_real: operand cannot be NULL");
1286 return di_is_zero(c->imag);
1287}
1288
1289DC_DEF bool dc_int_is_imag(dc_complex_int c) {
1290 DC_ASSERT(c && "dc_int_is_imag: operand cannot be NULL");
1291 return di_is_zero(c->real);
1292}
1293
1294DC_DEF char* dc_int_to_string(dc_complex_int c) {
1295 DC_ASSERT(c && "dc_int_to_string: operand cannot be NULL");
1296
1297 char* real_str = di_to_string(c->real, 10);
1298 char* imag_str = di_to_string(c->imag, 10);
1299
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");
1303
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);
1307
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");
1317 } else {
1318 sprintf(result, "%si", imag_str);
1319 }
1320 } else {
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);
1327 } else {
1328 sprintf(result, "%s+%si", real_str, imag_str);
1329 }
1330 }
1331
1332 free(real_str);
1333 free(imag_str);
1334
1335 return result;
1336}
1337
1338// ============================================================================
1339// FRACTION COMPLEX IMPLEMENTATION
1340// ============================================================================
1341
1342DC_DEF dc_complex_frac dc_frac_from_ints(int64_t real_num, int64_t real_den,
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);
1346 dc_complex_frac result = dc_frac_from_df(real, imag);
1347 df_release(&real);
1348 df_release(&imag);
1349 return result;
1350}
1351
1352DC_DEF dc_complex_frac dc_frac_from_df(df_frac real, df_frac imag) {
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");
1355
1356 dc_complex_frac result = DC_MALLOC(sizeof(struct dc_complex_frac_internal));
1357 DC_ASSERT(result && "dc_frac_from_df: allocation failed");
1358
1359 DC_ATOMIC_STORE(&result->ref_count, 1);
1360 result->real = df_retain(real);
1361 result->imag = df_retain(imag);
1362
1363 return result;
1364}
1365
1366DC_DEF dc_complex_frac dc_frac_zero(void) {
1367 if (!dc_frac_zero_singleton) {
1368 dc_frac_zero_singleton = dc_frac_from_ints(0, 1, 0, 1);
1369 DC_ATOMIC_STORE(&dc_frac_zero_singleton->ref_count, SIZE_MAX/2);
1370 }
1371 return dc_frac_retain(dc_frac_zero_singleton);
1372}
1373
1374DC_DEF dc_complex_frac dc_frac_one(void) {
1375 if (!dc_frac_one_singleton) {
1376 dc_frac_one_singleton = dc_frac_from_ints(1, 1, 0, 1);
1377 DC_ATOMIC_STORE(&dc_frac_one_singleton->ref_count, SIZE_MAX/2);
1378 }
1379 return dc_frac_retain(dc_frac_one_singleton);
1380}
1381
1382DC_DEF dc_complex_frac dc_frac_i(void) {
1383 if (!dc_frac_i_singleton) {
1384 dc_frac_i_singleton = dc_frac_from_ints(0, 1, 1, 1);
1385 DC_ATOMIC_STORE(&dc_frac_i_singleton->ref_count, SIZE_MAX/2);
1386 }
1387 return dc_frac_retain(dc_frac_i_singleton);
1388}
1389
1390DC_DEF dc_complex_frac dc_frac_neg_one(void) {
1391 if (!dc_frac_neg_one_singleton) {
1392 dc_frac_neg_one_singleton = dc_frac_from_ints(-1, 1, 0, 1);
1393 DC_ATOMIC_STORE(&dc_frac_neg_one_singleton->ref_count, SIZE_MAX/2);
1394 }
1395 return dc_frac_retain(dc_frac_neg_one_singleton);
1396}
1397
1398DC_DEF dc_complex_frac dc_frac_neg_i(void) {
1399 if (!dc_frac_neg_i_singleton) {
1400 dc_frac_neg_i_singleton = dc_frac_from_ints(0, 1, -1, 1);
1401 DC_ATOMIC_STORE(&dc_frac_neg_i_singleton->ref_count, SIZE_MAX/2);
1402 }
1403 return dc_frac_retain(dc_frac_neg_i_singleton);
1404}
1405
1407 DC_ASSERT(c && "dc_frac_retain: cannot retain NULL");
1408 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1409 return c;
1410}
1411
1412DC_DEF void dc_frac_release(dc_complex_frac* c) {
1413 if (!c || !*c) return;
1414
1415 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1416 if (old_count == 1) {
1417 // Don't free singletons
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) {
1421 *c = NULL;
1422 return;
1423 }
1424
1425 df_release(&(*c)->real);
1426 df_release(&(*c)->imag);
1427 DC_FREE(*c);
1428 }
1429 *c = NULL;
1430}
1431
1433 DC_ASSERT(c && "dc_frac_copy: cannot copy NULL");
1434 return dc_frac_from_df(c->real, c->imag);
1435}
1436
1438 DC_ASSERT(a && "dc_frac_add: first operand cannot be NULL");
1439 DC_ASSERT(b && "dc_frac_add: second operand cannot be NULL");
1440
1441 df_frac real = df_add(a->real, b->real);
1442 df_frac imag = df_add(a->imag, b->imag);
1443 dc_complex_frac result = dc_frac_from_df(real, imag);
1444 df_release(&real);
1445 df_release(&imag);
1446
1447 return result;
1448}
1449
1451 DC_ASSERT(a && "dc_frac_sub: first operand cannot be NULL");
1452 DC_ASSERT(b && "dc_frac_sub: second operand cannot be NULL");
1453
1454 df_frac real = df_sub(a->real, b->real);
1455 df_frac imag = df_sub(a->imag, b->imag);
1456 dc_complex_frac result = dc_frac_from_df(real, imag);
1457 df_release(&real);
1458 df_release(&imag);
1459
1460 return result;
1461}
1462
1464 DC_ASSERT(a && "dc_frac_mul: first operand cannot be NULL");
1465 DC_ASSERT(b && "dc_frac_mul: second operand cannot be NULL");
1466
1467 // (a + bi) * (c + di) = (ac - bd) + (ad + bc)i
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);
1472
1473 df_frac real = df_sub(ac, bd);
1474 df_frac imag = df_add(ad, bc);
1475
1476 dc_complex_frac result = dc_frac_from_df(real, imag);
1477
1478 df_release(&ac);
1479 df_release(&bd);
1480 df_release(&ad);
1481 df_release(&bc);
1482 df_release(&real);
1483 df_release(&imag);
1484
1485 return result;
1486}
1487
1489 DC_ASSERT(a && "dc_frac_div: first operand cannot be NULL");
1490 DC_ASSERT(b && "dc_frac_div: second operand cannot be NULL");
1491 DC_ASSERT(!dc_frac_is_zero(b) && "dc_frac_div: division by zero");
1492
1493 // (a + bi) / (c + di) = ((ac + bd) / (c² + d²)) + ((bc - ad) / (c² + d²))i
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);
1497
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);
1502
1503 df_frac real_num = df_add(ac, bd);
1504 df_frac imag_num = df_sub(bc, ad);
1505
1506 df_frac real = df_div(real_num, denom);
1507 df_frac imag = df_div(imag_num, denom);
1508
1509 dc_complex_frac result = dc_frac_from_df(real, imag);
1510
1511 df_release(&c2);
1512 df_release(&d2);
1513 df_release(&denom);
1514 df_release(&ac);
1515 df_release(&bd);
1516 df_release(&bc);
1517 df_release(&ad);
1518 df_release(&real_num);
1519 df_release(&imag_num);
1520 df_release(&real);
1521 df_release(&imag);
1522
1523 return result;
1524}
1525
1527 DC_ASSERT(c && "dc_frac_negate: operand cannot be NULL");
1528
1529 df_frac real = df_negate(c->real);
1530 df_frac imag = df_negate(c->imag);
1531 dc_complex_frac result = dc_frac_from_df(real, imag);
1532 df_release(&real);
1533 df_release(&imag);
1534
1535 return result;
1536}
1537
1539 DC_ASSERT(c && "dc_frac_conj: operand cannot be NULL");
1540
1541 df_frac real = df_retain(c->real);
1542 df_frac imag = df_negate(c->imag);
1543 dc_complex_frac result = dc_frac_from_df(real, imag);
1544 df_release(&real);
1545 df_release(&imag);
1546
1547 return result;
1548}
1549
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");
1553
1554 df_frac one = df_one();
1555 df_frac zero = df_zero();
1556 dc_complex_frac num = dc_frac_from_df(one, zero);
1557 dc_complex_frac result = dc_frac_div(num, c);
1558
1559 df_release(&one);
1560 df_release(&zero);
1561 dc_frac_release(&num);
1562
1563 return result;
1564}
1565
1566DC_DEF df_frac dc_frac_real(dc_complex_frac c) {
1567 DC_ASSERT(c && "dc_frac_real: operand cannot be NULL");
1568 return df_retain(c->real);
1569}
1570
1571DC_DEF df_frac dc_frac_imag(dc_complex_frac c) {
1572 DC_ASSERT(c && "dc_frac_imag: operand cannot be NULL");
1573 return df_retain(c->imag);
1574}
1575
1576DC_DEF bool dc_frac_eq(dc_complex_frac a, dc_complex_frac b) {
1577 DC_ASSERT(a && "dc_frac_eq: first operand cannot be NULL");
1578 DC_ASSERT(b && "dc_frac_eq: second operand cannot be NULL");
1579
1580 return df_eq(a->real, b->real) && df_eq(a->imag, b->imag);
1581}
1582
1583DC_DEF bool dc_frac_is_zero(dc_complex_frac c) {
1584 DC_ASSERT(c && "dc_frac_is_zero: operand cannot be NULL");
1585 return df_is_zero(c->real) && df_is_zero(c->imag);
1586}
1587
1588DC_DEF bool dc_frac_is_real(dc_complex_frac c) {
1589 DC_ASSERT(c && "dc_frac_is_real: operand cannot be NULL");
1590 return df_is_zero(c->imag);
1591}
1592
1593DC_DEF bool dc_frac_is_imag(dc_complex_frac c) {
1594 DC_ASSERT(c && "dc_frac_is_imag: operand cannot be NULL");
1595 return df_is_zero(c->real);
1596}
1597
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);
1601}
1602
1603DC_DEF char* dc_frac_to_string(dc_complex_frac c) {
1604 DC_ASSERT(c && "dc_frac_to_string: operand cannot be NULL");
1605
1606 char* real_str = df_to_string(c->real);
1607 char* imag_str = df_to_string(c->imag);
1608
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");
1612
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);
1616
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");
1628 } else {
1629 sprintf(result, "%si", imag_str);
1630 }
1631 df_release(&one);
1632 df_release(&neg_one);
1633 } else {
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);
1642 } else {
1643 sprintf(result, "%s+%si", real_str, imag_str);
1644 }
1645 df_release(&one);
1646 df_release(&neg_one);
1647 }
1648
1649 free(real_str);
1650 free(imag_str);
1651
1652 return result;
1653}
1654
1655// ============================================================================
1656// DOUBLE COMPLEX IMPLEMENTATION
1657// ============================================================================
1658
1659DC_DEF dc_complex_double dc_double_from_doubles(double real, double imag) {
1660 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1661 DC_ASSERT(result && "dc_double_from_doubles: allocation failed");
1662
1663 DC_ATOMIC_STORE(&result->ref_count, 1);
1664 result->value = real + imag * I;
1665
1666 return result;
1667}
1668
1669DC_DEF dc_complex_double dc_double_from_polar(double magnitude, double angle) {
1670 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1671 DC_ASSERT(result && "dc_double_from_polar: allocation failed");
1672
1673 DC_ATOMIC_STORE(&result->ref_count, 1);
1674 result->value = magnitude * cexp(I * angle);
1675
1676 return result;
1677}
1678
1679DC_DEF dc_complex_double dc_double_zero(void) {
1680 if (!dc_double_zero_singleton) {
1681 dc_double_zero_singleton = dc_double_from_doubles(0.0, 0.0);
1682 DC_ATOMIC_STORE(&dc_double_zero_singleton->ref_count, SIZE_MAX/2);
1683 }
1684 return dc_double_retain(dc_double_zero_singleton);
1685}
1686
1687DC_DEF dc_complex_double dc_double_one(void) {
1688 if (!dc_double_one_singleton) {
1689 dc_double_one_singleton = dc_double_from_doubles(1.0, 0.0);
1690 DC_ATOMIC_STORE(&dc_double_one_singleton->ref_count, SIZE_MAX/2);
1691 }
1692 return dc_double_retain(dc_double_one_singleton);
1693}
1694
1695DC_DEF dc_complex_double dc_double_i(void) {
1696 if (!dc_double_i_singleton) {
1697 dc_double_i_singleton = dc_double_from_doubles(0.0, 1.0);
1698 DC_ATOMIC_STORE(&dc_double_i_singleton->ref_count, SIZE_MAX/2);
1699 }
1700 return dc_double_retain(dc_double_i_singleton);
1701}
1702
1704 if (!dc_double_neg_one_singleton) {
1705 dc_double_neg_one_singleton = dc_double_from_doubles(-1.0, 0.0);
1706 DC_ATOMIC_STORE(&dc_double_neg_one_singleton->ref_count, SIZE_MAX/2);
1707 }
1708 return dc_double_retain(dc_double_neg_one_singleton);
1709}
1710
1712 if (!dc_double_neg_i_singleton) {
1713 dc_double_neg_i_singleton = dc_double_from_doubles(0.0, -1.0);
1714 DC_ATOMIC_STORE(&dc_double_neg_i_singleton->ref_count, SIZE_MAX/2);
1715 }
1716 return dc_double_retain(dc_double_neg_i_singleton);
1717}
1718
1720 DC_ASSERT(c && "dc_double_retain: cannot retain NULL");
1721 DC_ATOMIC_FETCH_ADD(&c->ref_count, 1);
1722 return c;
1723}
1724
1725DC_DEF void dc_double_release(dc_complex_double* c) {
1726 if (!c || !*c) return;
1727
1728 size_t old_count = DC_ATOMIC_FETCH_SUB(&(*c)->ref_count, 1);
1729 if (old_count == 1) {
1730 // Don't free singletons
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) {
1734 *c = NULL;
1735 return;
1736 }
1737
1738 DC_FREE(*c);
1739 }
1740 *c = NULL;
1741}
1742
1744 DC_ASSERT(c && "dc_double_copy: cannot copy NULL");
1745 return dc_double_from_doubles(creal(c->value), cimag(c->value));
1746}
1747
1749 DC_ASSERT(a && "dc_double_add: first operand cannot be NULL");
1750 DC_ASSERT(b && "dc_double_add: second operand cannot be NULL");
1751
1752 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1753 DC_ASSERT(result && "dc_double_add: allocation failed");
1754
1755 DC_ATOMIC_STORE(&result->ref_count, 1);
1756 result->value = a->value + b->value;
1757
1758 return result;
1759}
1760
1762 DC_ASSERT(a && "dc_double_sub: first operand cannot be NULL");
1763 DC_ASSERT(b && "dc_double_sub: second operand cannot be NULL");
1764
1765 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1766 DC_ASSERT(result && "dc_double_sub: allocation failed");
1767
1768 DC_ATOMIC_STORE(&result->ref_count, 1);
1769 result->value = a->value - b->value;
1770
1771 return result;
1772}
1773
1775 DC_ASSERT(a && "dc_double_mul: first operand cannot be NULL");
1776 DC_ASSERT(b && "dc_double_mul: second operand cannot be NULL");
1777
1778 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1779 DC_ASSERT(result && "dc_double_mul: allocation failed");
1780
1781 DC_ATOMIC_STORE(&result->ref_count, 1);
1782 result->value = a->value * b->value;
1783
1784 return result;
1785}
1786
1788 DC_ASSERT(a && "dc_double_div: first operand cannot be NULL");
1789 DC_ASSERT(b && "dc_double_div: second operand cannot be NULL");
1790 DC_ASSERT(!dc_double_is_zero(b) && "dc_double_div: division by zero");
1791
1792 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1793 DC_ASSERT(result && "dc_double_div: allocation failed");
1794
1795 DC_ATOMIC_STORE(&result->ref_count, 1);
1796 result->value = a->value / b->value;
1797
1798 return result;
1799}
1800
1802 DC_ASSERT(c && "dc_double_negate: operand cannot be NULL");
1803
1804 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1805 DC_ASSERT(result && "dc_double_negate: allocation failed");
1806
1807 DC_ATOMIC_STORE(&result->ref_count, 1);
1808 result->value = -c->value;
1809
1810 return result;
1811}
1812
1814 DC_ASSERT(c && "dc_double_conj: operand cannot be NULL");
1815
1816 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1817 DC_ASSERT(result && "dc_double_conj: allocation failed");
1818
1819 DC_ATOMIC_STORE(&result->ref_count, 1);
1820 result->value = conj(c->value);
1821
1822 return result;
1823}
1824
1826 DC_ASSERT(c && "dc_double_exp: operand cannot be NULL");
1827
1828 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1829 DC_ASSERT(result && "dc_double_exp: allocation failed");
1830
1831 DC_ATOMIC_STORE(&result->ref_count, 1);
1832 result->value = cexp(c->value);
1833
1834 return result;
1835}
1836
1838 DC_ASSERT(c && "dc_double_log: operand cannot be NULL");
1839 DC_ASSERT(!dc_double_is_zero(c) && "dc_double_log: log of zero");
1840
1841 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1842 DC_ASSERT(result && "dc_double_log: allocation failed");
1843
1844 DC_ATOMIC_STORE(&result->ref_count, 1);
1845 result->value = clog(c->value);
1846
1847 return result;
1848}
1849
1851 DC_ASSERT(a && "dc_double_pow: base cannot be NULL");
1852 DC_ASSERT(b && "dc_double_pow: exponent cannot be NULL");
1853
1854 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1855 DC_ASSERT(result && "dc_double_pow: allocation failed");
1856
1857 DC_ATOMIC_STORE(&result->ref_count, 1);
1858 result->value = cpow(a->value, b->value);
1859
1860 return result;
1861}
1862
1864 DC_ASSERT(c && "dc_double_sqrt: operand cannot be NULL");
1865
1866 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1867 DC_ASSERT(result && "dc_double_sqrt: allocation failed");
1868
1869 DC_ATOMIC_STORE(&result->ref_count, 1);
1870 result->value = csqrt(c->value);
1871
1872 return result;
1873}
1874
1876 DC_ASSERT(c && "dc_double_sin: operand cannot be NULL");
1877
1878 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1879 DC_ASSERT(result && "dc_double_sin: allocation failed");
1880
1881 DC_ATOMIC_STORE(&result->ref_count, 1);
1882 result->value = csin(c->value);
1883
1884 return result;
1885}
1886
1888 DC_ASSERT(c && "dc_double_cos: operand cannot be NULL");
1889
1890 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1891 DC_ASSERT(result && "dc_double_cos: allocation failed");
1892
1893 DC_ATOMIC_STORE(&result->ref_count, 1);
1894 result->value = ccos(c->value);
1895
1896 return result;
1897}
1898
1900 DC_ASSERT(c && "dc_double_tan: operand cannot be NULL");
1901
1902 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1903 DC_ASSERT(result && "dc_double_tan: allocation failed");
1904
1905 DC_ATOMIC_STORE(&result->ref_count, 1);
1906 result->value = ctan(c->value);
1907
1908 return result;
1909}
1910
1912 DC_ASSERT(c && "dc_double_sinh: operand cannot be NULL");
1913
1914 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1915 DC_ASSERT(result && "dc_double_sinh: allocation failed");
1916
1917 DC_ATOMIC_STORE(&result->ref_count, 1);
1918 result->value = csinh(c->value);
1919
1920 return result;
1921}
1922
1924 DC_ASSERT(c && "dc_double_cosh: operand cannot be NULL");
1925
1926 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1927 DC_ASSERT(result && "dc_double_cosh: allocation failed");
1928
1929 DC_ATOMIC_STORE(&result->ref_count, 1);
1930 result->value = ccosh(c->value);
1931
1932 return result;
1933}
1934
1936 DC_ASSERT(c && "dc_double_tanh: operand cannot be NULL");
1937
1938 dc_complex_double result = DC_MALLOC(sizeof(struct dc_complex_double_internal));
1939 DC_ASSERT(result && "dc_double_tanh: allocation failed");
1940
1941 DC_ATOMIC_STORE(&result->ref_count, 1);
1942 result->value = ctanh(c->value);
1943
1944 return result;
1945}
1946
1947DC_DEF double dc_double_real(dc_complex_double c) {
1948 DC_ASSERT(c && "dc_double_real: operand cannot be NULL");
1949 return creal(c->value);
1950}
1951
1952DC_DEF double dc_double_imag(dc_complex_double c) {
1953 DC_ASSERT(c && "dc_double_imag: operand cannot be NULL");
1954 return cimag(c->value);
1955}
1956
1957DC_DEF double dc_double_abs(dc_complex_double c) {
1958 DC_ASSERT(c && "dc_double_abs: operand cannot be NULL");
1959 return cabs(c->value);
1960}
1961
1962DC_DEF double dc_double_arg(dc_complex_double c) {
1963 DC_ASSERT(c && "dc_double_arg: operand cannot be NULL");
1964 return carg(c->value);
1965}
1966
1968 DC_ASSERT(a && "dc_double_eq: first operand cannot be NULL");
1969 DC_ASSERT(b && "dc_double_eq: second operand cannot be NULL");
1970
1971 return creal(a->value) == creal(b->value) && cimag(a->value) == cimag(b->value);
1972}
1973
1974DC_DEF bool dc_double_is_zero(dc_complex_double c) {
1975 DC_ASSERT(c && "dc_double_is_zero: operand cannot be NULL");
1976 return creal(c->value) == 0.0 && cimag(c->value) == 0.0;
1977}
1978
1979DC_DEF bool dc_double_is_real(dc_complex_double c) {
1980 DC_ASSERT(c && "dc_double_is_real: operand cannot be NULL");
1981 return cimag(c->value) == 0.0;
1982}
1983
1984DC_DEF bool dc_double_is_imag(dc_complex_double c) {
1985 DC_ASSERT(c && "dc_double_is_imag: operand cannot be NULL");
1986 return creal(c->value) == 0.0;
1987}
1988
1989DC_DEF bool dc_double_is_nan(dc_complex_double c) {
1990 DC_ASSERT(c && "dc_double_is_nan: operand cannot be NULL");
1991 return isnan(creal(c->value)) || isnan(cimag(c->value));
1992}
1993
1994DC_DEF bool dc_double_is_inf(dc_complex_double c) {
1995 DC_ASSERT(c && "dc_double_is_inf: operand cannot be NULL");
1996 return isinf(creal(c->value)) || isinf(cimag(c->value));
1997}
1998
1999DC_DEF char* dc_double_to_string(dc_complex_double c) {
2000 DC_ASSERT(c && "dc_double_to_string: operand cannot be NULL");
2001
2002 char* result = DC_MALLOC(256);
2003 DC_ASSERT(result && "dc_double_to_string: allocation failed");
2004
2005 double real = creal(c->value);
2006 double imag = cimag(c->value);
2007
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) {
2013 if (imag == 1.0) {
2014 strcpy(result, "i");
2015 } else if (imag == -1.0) {
2016 strcpy(result, "-i");
2017 } else {
2018 sprintf(result, "%gi", imag);
2019 }
2020 } else {
2021 if (imag == 1.0) {
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);
2027 } else {
2028 sprintf(result, "%g+%gi", real, imag);
2029 }
2030 }
2031
2032 return result;
2033}
2034
2035// ============================================================================
2036// TYPE CONVERSION IMPLEMENTATION
2037// ============================================================================
2038
2040 DC_ASSERT(c && "dc_int_to_frac: operand cannot be NULL");
2041
2042 df_frac real = df_from_di(c->real, di_one());
2043 df_frac imag = df_from_di(c->imag, di_one());
2044 dc_complex_frac result = dc_frac_from_df(real, imag);
2045
2046 df_release(&real);
2047 df_release(&imag);
2048
2049 return result;
2050}
2051
2053 DC_ASSERT(c && "dc_int_to_double: operand cannot be NULL");
2054
2055 double real = di_to_double(c->real);
2056 double imag = di_to_double(c->imag);
2057
2058 return dc_double_from_doubles(real, imag);
2059}
2060
2062 DC_ASSERT(c && "dc_frac_to_double: operand cannot be NULL");
2063
2064 double real = df_to_double(c->real);
2065 double imag = df_to_double(c->imag);
2066
2067 return dc_double_from_doubles(real, imag);
2068}
2069
2071 DC_ASSERT(c && "dc_frac_to_int: operand cannot be NULL");
2072
2073 // Convert to double and round
2074 double real = df_to_double(c->real);
2075 double imag = df_to_double(c->imag);
2076
2077 int64_t real_rounded = (int64_t)round(real);
2078 int64_t imag_rounded = (int64_t)round(imag);
2079
2080 return dc_int_from_ints(real_rounded, imag_rounded);
2081}
2082
2084 DC_ASSERT(c && "dc_double_to_int: operand cannot be NULL");
2085
2086 double real = creal(c->value);
2087 double imag = cimag(c->value);
2088
2089 int64_t real_rounded = (int64_t)round(real);
2090 int64_t imag_rounded = (int64_t)round(imag);
2091
2092 return dc_int_from_ints(real_rounded, imag_rounded);
2093}
2094
2095DC_DEF dc_complex_frac dc_double_to_frac(dc_complex_double c, int64_t max_denominator) {
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");
2098
2099 double real = creal(c->value);
2100 double imag = cimag(c->value);
2101
2102 df_frac real_frac = df_from_double(real, max_denominator);
2103 df_frac imag_frac = df_from_double(imag, max_denominator);
2104
2105 dc_complex_frac result = dc_frac_from_df(real_frac, imag_frac);
2106
2107 df_release(&real_frac);
2108 df_release(&imag_frac);
2109
2110 return result;
2111}
2112
2113#endif // DC_IMPLEMENTATION
2114
2115#endif // DYNAMIC_COMPLEX_H
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.