Dynamic Fraction Library 1.0.0
Reference-counted arbitrary precision rational number library (MIT OR Unlicense)
Loading...
Searching...
No Matches
dynamic_int.h
Go to the documentation of this file.
1
48#ifndef DYNAMIC_INT_H
49#define DYNAMIC_INT_H
50
51#include <stdint.h>
52#include <stddef.h>
53#include <stdbool.h>
54#include <limits.h>
55
56/* Configuration macros */
57#ifndef DI_MALLOC
58#define DI_MALLOC malloc
59#endif
60
61#ifndef DI_REALLOC
62#define DI_REALLOC realloc
63#endif
64
65#ifndef DI_FREE
66#define DI_FREE free
67#endif
68
69#ifndef DI_ASSERT
70#define DI_ASSERT assert
71#endif
72
73#ifndef DI_LIMB_BITS
74#define DI_LIMB_BITS 32
75#endif
76
77// API macros
78#ifdef DI_STATIC
79#define DI_DEF static
80#define DI_IMPL static
81#else
82#define DI_DEF extern
83#define DI_IMPL /* nothing - default linkage */
84#endif
85
86#if DI_LIMB_BITS == 32
87typedef uint32_t di_limb_t;
88typedef uint64_t di_dlimb_t; // Double-width for multiplication
89#define DI_LIMB_MAX UINT32_MAX
90#elif DI_LIMB_BITS == 16
91typedef uint16_t di_limb_t;
92typedef uint32_t di_dlimb_t;
93#define DI_LIMB_MAX UINT16_MAX
94#else
95#error "DI_LIMB_BITS must be 16 or 32"
96#endif
97
98// ============================================================================
99// INTERFACE
100// ============================================================================
101
113typedef struct di_int_internal* di_int;
114
140DI_DEF di_int di_from_int32(int32_t value);
141
159DI_DEF di_int di_from_int64(int64_t value);
160
170DI_DEF di_int di_from_uint32(uint32_t value);
171
181DI_DEF di_int di_from_uint64(uint64_t value);
182
204DI_DEF di_int di_from_string(const char* str, int base);
205
220DI_DEF di_int di_zero(void);
221
229DI_DEF di_int di_one(void);
230
249DI_DEF di_int di_copy(di_int big);
250
// end of creation_functions
252
277DI_DEF di_int di_retain(di_int big);
278
293DI_DEF void di_release(di_int* big);
294
303DI_DEF size_t di_ref_count(di_int big);
304
// end of reference_counting
306
333DI_DEF di_int di_add(di_int a, di_int b);
334
344DI_DEF di_int di_add_i32(di_int a, int32_t b);
345
356DI_DEF di_int di_sub(di_int a, di_int b);
357
367DI_DEF di_int di_sub_i32(di_int a, int32_t b);
368
379DI_DEF di_int di_mul(di_int a, di_int b);
380
390DI_DEF di_int di_mul_i32(di_int a, int32_t b);
391
415DI_DEF di_int di_div(di_int a, di_int b);
416
440DI_DEF di_int di_mod(di_int a, di_int b);
441
460DI_DEF di_int di_negate(di_int a);
461
471DI_DEF di_int di_abs(di_int a);
472
483DI_DEF di_int di_pow(di_int base, uint32_t exp);
484
// end of arithmetic_operations
486
500DI_DEF di_int di_and(di_int a, di_int b);
501
509DI_DEF di_int di_or(di_int a, di_int b);
510
518DI_DEF di_int di_xor(di_int a, di_int b);
519
526DI_DEF di_int di_not(di_int a);
527
535DI_DEF di_int di_shift_left(di_int a, size_t bits);
536
544DI_DEF di_int di_shift_right(di_int a, size_t bits);
545
// end of bitwise_operations
547
563DI_DEF int di_compare(di_int a, di_int b);
564
572DI_DEF bool di_eq(di_int a, di_int b);
573
581DI_DEF bool di_lt(di_int a, di_int b);
582
590DI_DEF bool di_le(di_int a, di_int b);
591
599DI_DEF bool di_gt(di_int a, di_int b);
600
608DI_DEF bool di_ge(di_int a, di_int b);
609
618DI_DEF bool di_is_zero(di_int big);
619
628DI_DEF bool di_is_negative(di_int big);
629
638DI_DEF bool di_is_positive(di_int big);
639
648DI_DEF bool di_is_one(di_int big);
649
// end of comparison_operations
651
676DI_DEF bool di_to_int32(di_int big, int32_t* result);
677
685DI_DEF bool di_to_int64(di_int big, int64_t* result);
686
694DI_DEF bool di_to_uint32(di_int big, uint32_t* result);
695
703DI_DEF bool di_to_uint64(di_int big, uint64_t* result);
704
714DI_DEF double di_to_double(di_int big);
715
734DI_DEF char* di_to_string(di_int big, int base);
735
// end of conversion_operations
737
750DI_DEF size_t di_bit_length(di_int big);
751
760DI_DEF size_t di_limb_count(di_int big);
761
788DI_DEF bool di_reserve(di_int big, size_t capacity);
789
// end of utility_functions
791
809DI_DEF di_int di_mod_pow(di_int base, di_int exp, di_int mod);
810
821DI_DEF di_int di_gcd(di_int a, di_int b);
822
833DI_DEF di_int di_lcm(di_int a, di_int b);
834
846DI_DEF di_int di_extended_gcd(di_int a, di_int b, di_int* x, di_int* y);
847
856DI_DEF di_int di_sqrt(di_int n);
857
869DI_DEF di_int di_factorial(uint32_t n);
870
// end of advanced_math
872
888DI_DEF bool di_is_prime(di_int n, int certainty);
889
896DI_DEF di_int di_next_prime(di_int n);
897
// end of prime_functions
899
915DI_DEF di_int di_random(size_t bits);
916
927DI_DEF di_int di_random_range(di_int min, di_int max);
928
// end of random_functions
930
956DI_DEF bool di_add_overflow_int32(int32_t a, int32_t b, int32_t* result);
957
966DI_DEF bool di_subtract_overflow_int32(int32_t a, int32_t b, int32_t* result);
967
976DI_DEF bool di_multiply_overflow_int32(int32_t a, int32_t b, int32_t* result);
977
986DI_DEF bool di_add_overflow_int64(int64_t a, int64_t b, int64_t* result);
987
996DI_DEF bool di_subtract_overflow_int64(int64_t a, int64_t b, int64_t* result);
997
1006DI_DEF bool di_multiply_overflow_int64(int64_t a, int64_t b, int64_t* result);
1007
// end of overflow_detection
1009
1010#ifdef DI_IMPLEMENTATION
1011
1012#include <stdlib.h>
1013#include <string.h>
1014#include <assert.h>
1015#include <stdio.h>
1016#include <math.h>
1017
1018/* Internal structure */
1019struct di_int_internal {
1020 size_t ref_count; // Reference count
1021 di_limb_t* limbs; // Array of limbs (little-endian)
1022 size_t limb_count; // Number of limbs used
1023 size_t limb_capacity; // Allocated capacity
1024 bool is_negative; // Sign flag
1025};
1026
1027/* Internal function declarations */
1028static void di_resize_internal(struct di_int_internal* big, size_t new_capacity);
1029
1030/* Internal helper functions */
1031
1032static struct di_int_internal* di_alloc(size_t initial_capacity) {
1033 struct di_int_internal* big = (struct di_int_internal*)DI_MALLOC(sizeof(struct di_int_internal));
1034 DI_ASSERT(big && "di_alloc: memory allocation failed");
1035
1036 big->ref_count = 1;
1037 big->limb_count = 0;
1038 big->limb_capacity = initial_capacity;
1039 big->is_negative = false;
1040
1041 if (initial_capacity > 0) {
1042 big->limbs = (di_limb_t*)DI_MALLOC(sizeof(di_limb_t) * initial_capacity);
1043 DI_ASSERT(big->limbs && "di_alloc: limb array allocation failed");
1044 memset(big->limbs, 0, sizeof(di_limb_t) * initial_capacity);
1045 } else {
1046 big->limbs = NULL;
1047 }
1048
1049 return big;
1050}
1051
1052static void di_normalize(struct di_int_internal* big) {
1053 // Remove leading zeros
1054 while (big->limb_count > 0 && big->limbs[big->limb_count - 1] == 0) {
1055 big->limb_count--;
1056 }
1057
1058 // Zero should not be negative
1059 if (big->limb_count == 0) {
1060 big->is_negative = false;
1061 }
1062}
1063
1064DI_IMPL bool di_reserve(di_int big, size_t capacity) {
1065 DI_ASSERT(big && "di_reserve: operand cannot be NULL");
1066
1067 di_resize_internal(big, capacity);
1068 return true;
1069}
1070
1071static void di_resize_internal(struct di_int_internal* big, size_t new_capacity) {
1072 if (new_capacity <= big->limb_capacity) return;
1073
1074 di_limb_t* new_limbs = (di_limb_t*)DI_REALLOC(big->limbs, sizeof(di_limb_t) * new_capacity);
1075 DI_ASSERT(new_limbs && "di_resize_internal: reallocation failed");
1076
1077 // Zero out new limbs
1078 memset(new_limbs + big->limb_capacity, 0, sizeof(di_limb_t) * (new_capacity - big->limb_capacity));
1079
1080 big->limbs = new_limbs;
1081 big->limb_capacity = new_capacity;
1082}
1083
1084/* Creation functions */
1085
1086DI_IMPL di_int di_from_int32(int32_t value) {
1087 struct di_int_internal* big = di_alloc(1);
1088 DI_ASSERT(big && "di_from_int32: allocation failed");
1089
1090 if (value < 0) {
1091 big->is_negative = true;
1092 // Handle INT32_MIN carefully
1093 if (value == INT32_MIN) {
1094 big->limbs[0] = (di_limb_t)INT32_MAX + 1;
1095 } else {
1096 big->limbs[0] = (di_limb_t)(-value);
1097 }
1098 } else {
1099 big->limbs[0] = (di_limb_t)value;
1100 }
1101 big->limb_count = (value != 0) ? 1 : 0;
1102
1103 return big;
1104}
1105
1106DI_IMPL di_int di_from_int64(int64_t value) {
1107 struct di_int_internal* big = di_alloc(2);
1108 DI_ASSERT(big && "di_from_int64: allocation failed");
1109
1110 if (value < 0) {
1111 big->is_negative = true;
1112 // Handle INT64_MIN carefully
1113 if (value == INT64_MIN) {
1114 uint64_t uval = (uint64_t)INT64_MAX + 1;
1115 big->limbs[0] = (di_limb_t)(uval & DI_LIMB_MAX);
1116 big->limbs[1] = (di_limb_t)(uval >> DI_LIMB_BITS);
1117 } else {
1118 uint64_t uval = (uint64_t)(-value);
1119 big->limbs[0] = (di_limb_t)(uval & DI_LIMB_MAX);
1120 big->limbs[1] = (di_limb_t)(uval >> DI_LIMB_BITS);
1121 }
1122 } else {
1123 uint64_t uval = (uint64_t)value;
1124 big->limbs[0] = (di_limb_t)(uval & DI_LIMB_MAX);
1125 big->limbs[1] = (di_limb_t)(uval >> DI_LIMB_BITS);
1126 }
1127
1128 big->limb_count = 2;
1129 di_normalize(big);
1130
1131 return big;
1132}
1133
1134DI_IMPL di_int di_from_uint32(uint32_t value) {
1135 struct di_int_internal* big = di_alloc(1);
1136 DI_ASSERT(big && "di_from_uint32: allocation failed");
1137
1138 big->limbs[0] = value;
1139 big->limb_count = (value != 0) ? 1 : 0;
1140 big->is_negative = false;
1141
1142 return big;
1143}
1144
1145DI_IMPL di_int di_from_uint64(uint64_t value) {
1146 struct di_int_internal* big = di_alloc(2);
1147 DI_ASSERT(big && "di_from_uint64: allocation failed");
1148
1149 big->limbs[0] = (di_limb_t)(value & DI_LIMB_MAX);
1150 big->limbs[1] = (di_limb_t)(value >> DI_LIMB_BITS);
1151 big->limb_count = 2;
1152 big->is_negative = false;
1153 di_normalize(big);
1154
1155 return big;
1156}
1157
1158DI_IMPL di_int di_zero(void) {
1159 return di_from_int32(0);
1160}
1161
1162DI_IMPL di_int di_one(void) {
1163 return di_from_int32(1);
1164}
1165
1166DI_IMPL di_int di_copy(di_int big) {
1167 DI_ASSERT(big && "di_copy: operand cannot be NULL");
1168
1169 struct di_int_internal* copy = di_alloc(big->limb_capacity);
1170
1171 copy->limb_count = big->limb_count;
1172 copy->is_negative = big->is_negative;
1173 if (big->limb_count > 0) {
1174 memcpy(copy->limbs, big->limbs, sizeof(di_limb_t) * big->limb_count);
1175 }
1176
1177 return copy;
1178}
1179
1180DI_IMPL di_int di_from_string(const char* str, int base) {
1181 DI_ASSERT(str && "di_from_string: string cannot be NULL");
1182 DI_ASSERT(base >= 2 && base <= 36 && "di_from_string: invalid base");
1183
1184 // Skip whitespace
1185 while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r') str++;
1186 DI_ASSERT(*str != '\0' && "di_from_string: empty string");
1187
1188 // Check for sign
1189 bool is_negative = false;
1190 if (*str == '-') {
1191 is_negative = true;
1192 str++;
1193 } else if (*str == '+') {
1194 str++;
1195 }
1196
1197 // Skip leading zeros
1198 while (*str == '0') str++;
1199 if (*str == '\0') return di_zero();
1200
1201 // Count valid digits to estimate capacity
1202 const char* p = str;
1203 size_t digit_count = 0;
1204 while (*p) {
1205 char c = *p;
1206 int digit_val;
1207 if (c >= '0' && c <= '9') {
1208 digit_val = c - '0';
1209 } else if (c >= 'a' && c <= 'z') {
1210 digit_val = c - 'a' + 10;
1211 } else if (c >= 'A' && c <= 'Z') {
1212 digit_val = c - 'A' + 10;
1213 } else {
1214 break; // Invalid character
1215 }
1216
1217 if (digit_val >= base) break; // Invalid digit for this base
1218 digit_count++;
1219 p++;
1220 }
1221
1222 if (digit_count == 0) return NULL;
1223
1224 // Estimate capacity: log2(base^n) = n * log2(base)
1225 // Rough estimate: each decimal digit needs ~3.32 bits, so use digit_count limbs
1226 size_t capacity = (digit_count + 7) / 8 + 1; // Conservative estimate
1227 if (capacity < 1) capacity = 1;
1228
1229 struct di_int_internal* result = di_alloc(capacity);
1230 DI_ASSERT(result && "di_from_string: allocation failed");
1231
1232 // Convert digit by digit using Horner's method: result = result * base + digit
1233 di_int base_big = di_from_int32(base);
1234 DI_ASSERT(base_big && "di_from_string: base allocation failed");
1235
1236 p = str;
1237 for (size_t i = 0; i < digit_count; i++) {
1238 char c = *p++;
1239 int digit_val;
1240 if (c >= '0' && c <= '9') {
1241 digit_val = c - '0';
1242 } else if (c >= 'a' && c <= 'z') {
1243 digit_val = c - 'a' + 10;
1244 } else if (c >= 'A' && c <= 'Z') {
1245 digit_val = c - 'A' + 10;
1246 } else {
1247 break;
1248 }
1249
1250 // result = result * base + digit
1251 di_int temp = di_mul(result, base_big);
1252 DI_ASSERT(temp && "di_from_string: multiplication allocation failed");
1253
1254 di_int digit_big = di_from_int32(digit_val);
1255 DI_ASSERT(digit_big && "di_from_string: digit allocation failed");
1256
1257 di_int new_result = di_add(temp, digit_big);
1258 di_release(&temp);
1259 di_release(&digit_big);
1260
1261 DI_ASSERT(new_result && "di_from_string: addition allocation failed");
1262
1263 di_release((di_int*)&result);
1264 result = new_result;
1265 }
1266
1267 di_release(&base_big);
1268
1269 // Set sign
1270 if (is_negative && result->limb_count > 0) {
1271 result->is_negative = true;
1272 }
1273
1274 return result;
1275}
1276
1277/* Reference counting */
1278
1280 DI_ASSERT(big && "di_retain: operand cannot be NULL");
1281 big->ref_count++;
1282 return big;
1283}
1284
1285DI_IMPL void di_release(di_int* big) {
1286 if (!big || !*big) return;
1287
1288 struct di_int_internal* b = *big;
1289 if (--b->ref_count == 0) {
1290 if (b->limbs) {
1291 DI_FREE(b->limbs);
1292 }
1293 DI_FREE(b);
1294 }
1295 *big = NULL;
1296}
1297
1298DI_IMPL size_t di_ref_count(di_int big) {
1299 DI_ASSERT(big && "di_ref_count: operand cannot be NULL");
1300 return big->ref_count;
1301}
1302
1303/* Comparison functions */
1304
1305DI_IMPL int di_compare(di_int a, di_int b) {
1306 DI_ASSERT(a && "di_compare: first operand cannot be NULL");
1307 DI_ASSERT(b && "di_compare: second operand cannot be NULL");
1308
1309 // Compare signs
1310 if (a->is_negative != b->is_negative) {
1311 return a->is_negative ? -1 : 1;
1312 }
1313
1314 // Same sign, compare magnitudes
1315 if (a->limb_count != b->limb_count) {
1316 int mag_cmp = (a->limb_count > b->limb_count) ? 1 : -1;
1317 return a->is_negative ? -mag_cmp : mag_cmp;
1318 }
1319
1320 // Same number of limbs, compare from most significant
1321 for (size_t i = a->limb_count; i > 0; i--) {
1322 if (a->limbs[i-1] > b->limbs[i-1]) {
1323 return a->is_negative ? -1 : 1;
1324 }
1325 if (a->limbs[i-1] < b->limbs[i-1]) {
1326 return a->is_negative ? 1 : -1;
1327 }
1328 }
1329
1330 return 0; // Equal
1331}
1332
1333DI_IMPL bool di_eq(di_int a, di_int b) {
1334 return di_compare(a, b) == 0;
1335}
1336
1337DI_IMPL bool di_lt(di_int a, di_int b) {
1338 return di_compare(a, b) < 0;
1339}
1340
1341DI_IMPL bool di_le(di_int a, di_int b) {
1342 return di_compare(a, b) <= 0;
1343}
1344
1345DI_IMPL bool di_gt(di_int a, di_int b) {
1346 return di_compare(a, b) > 0;
1347}
1348
1349DI_IMPL bool di_ge(di_int a, di_int b) {
1350 return di_compare(a, b) >= 0;
1351}
1352
1353DI_IMPL bool di_is_zero(di_int big) {
1354 DI_ASSERT(big && "di_is_zero: operand cannot be NULL");
1355 return big->limb_count == 0;
1356}
1357
1358DI_IMPL bool di_is_negative(di_int big) {
1359 DI_ASSERT(big && "di_is_negative: operand cannot be NULL");
1360 return big->is_negative && big->limb_count > 0;
1361}
1362
1363DI_IMPL bool di_is_positive(di_int big) {
1364 DI_ASSERT(big && "di_is_positive: operand cannot be NULL");
1365 return !big->is_negative && big->limb_count > 0;
1366}
1367
1368DI_IMPL bool di_is_one(di_int big) {
1369 DI_ASSERT(big && "di_is_one: operand cannot be NULL");
1370 if (big->is_negative || big->limb_count != 1) {
1371 return false;
1372 }
1373 return big->limbs[0] == 1;
1374}
1375
1376/* Conversion functions */
1377
1378DI_IMPL bool di_to_int32(di_int big, int32_t* result) {
1379 DI_ASSERT(big && "di_to_int32: integer cannot be NULL");
1380 DI_ASSERT(result && "di_to_int32: result pointer cannot be NULL");
1381
1382 if (big->limb_count == 0) {
1383 *result = 0;
1384 return true;
1385 }
1386
1387 if (big->limb_count > 1) return false;
1388
1389 di_limb_t val = big->limbs[0];
1390
1391 if (big->is_negative) {
1392 if (val > (di_limb_t)INT32_MAX + 1) return false;
1393 if (val == (di_limb_t)INT32_MAX + 1) {
1394 *result = INT32_MIN;
1395 } else {
1396 *result = -(int32_t)val;
1397 }
1398 } else {
1399 if (val > INT32_MAX) return false;
1400 *result = (int32_t)val;
1401 }
1402
1403 return true;
1404}
1405
1406DI_IMPL bool di_to_int64(di_int big, int64_t* result) {
1407 DI_ASSERT(big && "di_to_int64: integer cannot be NULL");
1408 DI_ASSERT(result && "di_to_int64: result pointer cannot be NULL");
1409
1410 if (big->limb_count == 0) {
1411 *result = 0;
1412 return true;
1413 }
1414
1415 if (big->limb_count > 2) return false;
1416
1417 uint64_t val = big->limbs[0];
1418 if (big->limb_count == 2) {
1419 val |= ((uint64_t)big->limbs[1] << DI_LIMB_BITS);
1420 }
1421
1422 if (big->is_negative) {
1423 if (val > (uint64_t)INT64_MAX + 1) return false;
1424 if (val == (uint64_t)INT64_MAX + 1) {
1425 *result = INT64_MIN;
1426 } else {
1427 *result = -(int64_t)val;
1428 }
1429 } else {
1430 if (val > INT64_MAX) return false;
1431 *result = (int64_t)val;
1432 }
1433
1434 return true;
1435}
1436
1437DI_IMPL bool di_to_uint32(di_int big, uint32_t* result) {
1438 DI_ASSERT(big && "di_to_uint32: integer cannot be NULL");
1439 DI_ASSERT(result && "di_to_uint32: result pointer cannot be NULL");
1440
1441 if (big->limb_count == 0) {
1442 *result = 0;
1443 return true;
1444 }
1445
1446 // Negative numbers cannot be converted to unsigned
1447 if (big->is_negative) return false;
1448
1449 // Check if value fits in uint32
1450 if (big->limb_count > 1) {
1451 // If more than 1 limb, check if the value exceeds uint32 max
1452 if (big->limb_count > 2) return false;
1453 uint64_t val = big->limbs[0] | ((uint64_t)big->limbs[1] << DI_LIMB_BITS);
1454 if (val > UINT32_MAX) return false;
1455 *result = (uint32_t)val;
1456 } else {
1457 // Single limb case
1458 if (sizeof(di_limb_t) > sizeof(uint32_t) && big->limbs[0] > UINT32_MAX) {
1459 return false;
1460 }
1461 *result = (uint32_t)big->limbs[0];
1462 }
1463
1464 return true;
1465}
1466
1467DI_IMPL bool di_to_uint64(di_int big, uint64_t* result) {
1468 DI_ASSERT(big && "di_to_uint64: integer cannot be NULL");
1469 DI_ASSERT(result && "di_to_uint64: result pointer cannot be NULL");
1470
1471 if (big->limb_count == 0) {
1472 *result = 0;
1473 return true;
1474 }
1475
1476 // Negative numbers cannot be converted to unsigned
1477 if (big->is_negative) return false;
1478
1479 // Check if value fits in uint64
1480 if (big->limb_count > 2) return false;
1481
1482 uint64_t val = big->limbs[0];
1483 if (big->limb_count == 2) {
1484 val |= ((uint64_t)big->limbs[1] << DI_LIMB_BITS);
1485 }
1486
1487 *result = val;
1488 return true;
1489}
1490
1491DI_IMPL double di_to_double(di_int big) {
1492 DI_ASSERT(big && "di_to_double: operand cannot be NULL");
1493 if (big->limb_count == 0) return 0.0;
1494
1495 double result = 0.0;
1496 double base = 1.0;
1497
1498 for (size_t i = 0; i < big->limb_count; i++) {
1499 result += big->limbs[i] * base;
1500 base *= (double)(DI_LIMB_MAX + 1ULL);
1501 }
1502
1503 return big->is_negative ? -result : result;
1504}
1505
1506/* Helper function to compare magnitudes (ignoring sign) */
1507static int di_compare_magnitude(struct di_int_internal* a, struct di_int_internal* b) {
1508 if (a->limb_count > b->limb_count) return 1;
1509 if (a->limb_count < b->limb_count) return -1;
1510
1511 // Same number of limbs - compare from most significant
1512 for (size_t i = a->limb_count; i > 0; i--) {
1513 size_t idx = i - 1;
1514 if (a->limbs[idx] > b->limbs[idx]) return 1;
1515 if (a->limbs[idx] < b->limbs[idx]) return -1;
1516 }
1517
1518 return 0; // Equal magnitudes
1519}
1520
1521/* Basic arithmetic implementations */
1522
1524 DI_ASSERT(a != NULL && "di_add: first operand cannot be NULL");
1525 DI_ASSERT(b != NULL && "di_add: second operand cannot be NULL");
1526
1527 // Simple implementation for same-sign addition
1528 if (a->is_negative == b->is_negative) {
1529 struct di_int_internal* result = di_alloc(
1530 (a->limb_count > b->limb_count ? a->limb_count : b->limb_count) + 1
1531 );
1532 DI_ASSERT(result && "di_add: allocation failed");
1533
1534 result->is_negative = a->is_negative;
1535
1536 di_dlimb_t carry = 0;
1537 size_t max_limbs = a->limb_count > b->limb_count ? a->limb_count : b->limb_count;
1538
1539 for (size_t i = 0; i < max_limbs; i++) {
1540 di_dlimb_t sum = carry;
1541 if (i < a->limb_count) sum += a->limbs[i];
1542 if (i < b->limb_count) sum += b->limbs[i];
1543
1544 result->limbs[i] = (di_limb_t)(sum & DI_LIMB_MAX);
1545 carry = sum >> DI_LIMB_BITS;
1546 }
1547
1548 if (carry) {
1549 result->limbs[max_limbs] = (di_limb_t)carry;
1550 result->limb_count = max_limbs + 1;
1551 } else {
1552 result->limb_count = max_limbs;
1553 }
1554
1555 di_normalize(result);
1556 return result;
1557 }
1558
1559 // Different signs - subtract magnitudes
1560 // First determine which has larger magnitude
1561 int cmp = di_compare_magnitude(a, b);
1562
1563 struct di_int_internal* larger = (cmp >= 0) ? a : b;
1564 struct di_int_internal* smaller = (cmp >= 0) ? b : a;
1565
1566 // Result takes sign of the larger magnitude operand
1567 // If a has larger magnitude: result = a - b (sign of a)
1568 // If b has larger magnitude: result = -(b - a) = b - a with opposite sign
1569 bool result_negative = (cmp >= 0) ? a->is_negative : b->is_negative;
1570
1571 // Subtract smaller magnitude from larger magnitude
1572 struct di_int_internal* result = di_alloc(larger->limb_count);
1573 DI_ASSERT(result && "di_sub: allocation failed");
1574
1575 result->is_negative = result_negative;
1576 result->limb_count = larger->limb_count;
1577
1578 di_limb_t borrow = 0;
1579 for (size_t i = 0; i < result->limb_count; i++) {
1580 di_limb_t a_limb = (i < larger->limb_count) ? larger->limbs[i] : 0;
1581 di_limb_t b_limb = (i < smaller->limb_count) ? smaller->limbs[i] : 0;
1582
1583 // Use signed arithmetic to detect underflow
1584 int64_t signed_diff = (int64_t)a_limb - (int64_t)b_limb - (int64_t)borrow;
1585
1586 di_dlimb_t diff;
1587 if (signed_diff < 0) {
1588 diff = (di_dlimb_t)(signed_diff + (1ULL << DI_LIMB_BITS));
1589 borrow = 1;
1590 } else {
1591 diff = (di_dlimb_t)signed_diff;
1592 borrow = 0;
1593 }
1594
1595 result->limbs[i] = (di_limb_t)diff;
1596 }
1597
1598 di_normalize(result);
1599 return result;
1600}
1601
1602DI_IMPL di_int di_add_i32(di_int a, int32_t b) {
1603 DI_ASSERT(a && "di_add_i32: operand cannot be NULL");
1604
1605 // Convert int32 to big integer and use regular addition
1606 di_int b_big = di_from_int32(b);
1607 DI_ASSERT(b_big && "di_add_i32: allocation failed");
1608
1609 di_int result = di_add(a, b_big);
1610 di_release(&b_big);
1611 return result;
1612}
1613
1615 DI_ASSERT(a != NULL && "di_sub: first operand cannot be NULL");
1616 DI_ASSERT(b != NULL && "di_sub: second operand cannot be NULL");
1617
1618 // a - b = a + (-b)
1619 di_int neg_b = di_negate(b);
1620 DI_ASSERT(neg_b && "di_sub: allocation failed");
1621
1622 di_int result = di_add(a, neg_b);
1623 di_release(&neg_b);
1624 return result;
1625}
1626
1627DI_IMPL di_int di_sub_i32(di_int a, int32_t b) {
1628 DI_ASSERT(a && "di_sub_i32: operand cannot be NULL");
1629
1630 // Convert int32 to big integer and use regular subtraction
1631 di_int b_big = di_from_int32(b);
1632 DI_ASSERT(b_big && "di_sub_i32: allocation failed");
1633
1634 di_int result = di_sub(a, b_big);
1635 di_release(&b_big);
1636 return result;
1637}
1638
1640 DI_ASSERT(a && "di_negate: operand cannot be NULL");
1641
1642 di_int result = di_copy(a);
1643 if (result && result->limb_count > 0) {
1644 result->is_negative = !result->is_negative;
1645 }
1646 return result;
1647}
1648
1649/* String conversion implementation */
1650DI_IMPL char* di_to_string(di_int big, int base) {
1651 DI_ASSERT(big && "di_to_string: operand cannot be NULL");
1652 DI_ASSERT(base >= 2 && base <= 36 && "di_to_string: invalid base");
1653
1654 if (big->limb_count == 0) {
1655 char* str = (char*)DI_MALLOC(2);
1656 DI_ASSERT(str && "di_to_string: allocation failed for zero string");
1657 str[0] = '0';
1658 str[1] = '\0';
1659 return str;
1660 }
1661
1662 // Simple implementation for base 10
1663 if (base == 10) {
1664 // Proper arbitrary precision decimal conversion using efficient modular arithmetic
1665 size_t max_digits = big->limb_count * 10 + 10;
1666 char* buffer = (char*)DI_MALLOC(max_digits);
1667 DI_ASSERT(buffer && "di_to_string: buffer allocation failed");
1668
1669 // Make a working copy
1670 di_int work = di_copy(big);
1671
1672 char* digits = (char*)DI_MALLOC(max_digits);
1673 DI_ASSERT(digits && "di_to_string: digits allocation failed");
1674
1675 size_t digit_count = 0;
1676
1677 // Handle zero case
1678 if (di_is_zero(work)) {
1679 buffer[0] = '0';
1680 buffer[1] = '\0';
1681 DI_FREE(digits);
1682 di_release(&work);
1683 return buffer;
1684 }
1685
1686 // Extract digits using limb-level division by 10 (much more efficient than di_div)
1687 while (!di_is_zero(work)) {
1688 // Divide by 10 using limb arithmetic
1689 di_dlimb_t remainder = 0;
1690 for (int i = (int)work->limb_count - 1; i >= 0; i--) {
1691 di_dlimb_t temp = remainder * ((di_dlimb_t)DI_LIMB_MAX + 1) + work->limbs[i];
1692 work->limbs[i] = (di_limb_t)(temp / 10);
1693 remainder = temp % 10;
1694 }
1695
1696 // Store the digit
1697 digits[digit_count++] = '0' + (char)remainder;
1698
1699 // Remove leading zeros
1700 while (work->limb_count > 0 && work->limbs[work->limb_count - 1] == 0) {
1701 work->limb_count--;
1702 }
1703 }
1704
1705 // Build result string (digits are in reverse order)
1706 size_t pos = 0;
1707 if (big->is_negative) {
1708 buffer[pos++] = '-';
1709 }
1710
1711 for (size_t i = digit_count; i > 0; i--) {
1712 buffer[pos++] = digits[i - 1];
1713 }
1714 buffer[pos] = '\0';
1715
1716 DI_FREE(digits);
1717 di_release(&work);
1718
1719 return buffer;
1720 }
1721
1722 return NULL;
1723}
1724
1725/* Overflow detection helpers */
1726
1727DI_IMPL bool di_add_overflow_int32(int32_t a, int32_t b, int32_t* result) {
1728 DI_ASSERT(result && "di_add_overflow_int32: result pointer cannot be NULL");
1729 int64_t sum = (int64_t)a + (int64_t)b;
1730 if (sum < INT32_MIN || sum > INT32_MAX) {
1731 return false; // Overflow
1732 }
1733 *result = (int32_t)sum;
1734 return true;
1735}
1736
1737DI_IMPL bool di_subtract_overflow_int32(int32_t a, int32_t b, int32_t* result) {
1738 DI_ASSERT(result && "di_subtract_overflow_int32: result pointer cannot be NULL");
1739 int64_t diff = (int64_t)a - (int64_t)b;
1740 if (diff < INT32_MIN || diff > INT32_MAX) {
1741 return false; // Overflow
1742 }
1743 *result = (int32_t)diff;
1744 return true;
1745}
1746
1747DI_IMPL bool di_multiply_overflow_int32(int32_t a, int32_t b, int32_t* result) {
1748 DI_ASSERT(result && "di_multiply_overflow_int32: result pointer cannot be NULL");
1749 int64_t prod = (int64_t)a * (int64_t)b;
1750 if (prod < INT32_MIN || prod > INT32_MAX) {
1751 return false; // Overflow
1752 }
1753 *result = (int32_t)prod;
1754 return true;
1755}
1756
1757DI_IMPL bool di_add_overflow_int64(int64_t a, int64_t b, int64_t* result) {
1758 DI_ASSERT(result && "di_add_overflow_int64: result pointer cannot be NULL");
1759 // Check for overflow without causing UB
1760 if (b > 0 && a > INT64_MAX - b) return false;
1761 if (b < 0 && a < INT64_MIN - b) return false;
1762 *result = a + b;
1763 return true;
1764}
1765
1766DI_IMPL bool di_subtract_overflow_int64(int64_t a, int64_t b, int64_t* result) {
1767 DI_ASSERT(result && "di_subtract_overflow_int64: result pointer cannot be NULL");
1768 // Check for overflow without causing UB
1769 if (b < 0 && a > INT64_MAX + b) return false;
1770 if (b > 0 && a < INT64_MIN + b) return false;
1771 *result = a - b;
1772 return true;
1773}
1774
1775DI_IMPL bool di_multiply_overflow_int64(int64_t a, int64_t b, int64_t* result) {
1776 DI_ASSERT(result && "di_multiply_overflow_int64: result pointer cannot be NULL");
1777 // Check for overflow - this is complex for 64-bit
1778 if (a == 0 || b == 0) {
1779 *result = 0;
1780 return true;
1781 }
1782
1783 // Check if multiplication would overflow
1784 if (a > 0) {
1785 if (b > 0) {
1786 if (a > INT64_MAX / b) return false;
1787 } else {
1788 if (b < INT64_MIN / a) return false;
1789 }
1790 } else {
1791 if (b > 0) {
1792 if (a < INT64_MIN / b) return false;
1793 } else {
1794 if (a != 0 && b < INT64_MAX / a) return false;
1795 }
1796 }
1797
1798 *result = a * b;
1799 return true;
1800}
1801
1802// Big integer multiplication - use the original working approach for single limb case, full algorithm for multi-limb
1804 DI_ASSERT(a != NULL && "di_mul: first operand cannot be NULL");
1805 DI_ASSERT(b != NULL && "di_mul: second operand cannot be NULL");
1806
1807 // Handle zero cases
1808 if (a->limb_count == 0 || b->limb_count == 0) {
1809 return di_from_int32(0);
1810 }
1811
1812 // For single limb x single limb, use direct 64-bit multiplication (should be exact)
1813 if (a->limb_count == 1 && b->limb_count == 1) {
1814 di_dlimb_t product = (di_dlimb_t)a->limbs[0] * (di_dlimb_t)b->limbs[0];
1815 bool result_negative = (a->is_negative != b->is_negative);
1816
1817 if (product <= DI_LIMB_MAX) {
1818 // Result fits in one limb
1819 di_int result = di_from_uint32((uint32_t)product);
1820 if (result && result_negative && product > 0) {
1821 result->is_negative = true;
1822 }
1823 return result;
1824 } else {
1825 // Result needs two limbs
1826 struct di_int_internal* result = di_alloc(2);
1827 DI_ASSERT(result && "di_mul: allocation failed");
1828
1829 result->is_negative = result_negative;
1830 result->limb_count = 2;
1831 result->limbs[0] = (di_limb_t)(product & DI_LIMB_MAX);
1832 result->limbs[1] = (di_limb_t)(product >> DI_LIMB_BITS);
1833
1834 di_normalize(result);
1835 return result;
1836 }
1837 }
1838
1839 // For multi-limb cases, use proper schoolbook multiplication
1840 bool result_negative = (a->is_negative != b->is_negative);
1841 size_t result_capacity = a->limb_count + b->limb_count;
1842 struct di_int_internal* result = di_alloc(result_capacity);
1843 DI_ASSERT(result && "di_mul: allocation failed");
1844
1845 result->is_negative = result_negative;
1846 result->limb_count = result_capacity;
1847
1848 // Initialize result to zero
1849 for (size_t i = 0; i < result_capacity; i++) {
1850 result->limbs[i] = 0;
1851 }
1852
1853 // Schoolbook multiplication
1854 for (size_t i = 0; i < a->limb_count; i++) {
1855 di_dlimb_t carry = 0;
1856
1857 for (size_t j = 0; j < b->limb_count; j++) {
1858 size_t pos = i + j;
1859 di_dlimb_t prod = (di_dlimb_t)a->limbs[i] * (di_dlimb_t)b->limbs[j];
1860 di_dlimb_t sum = (di_dlimb_t)result->limbs[pos] + prod + carry;
1861
1862 result->limbs[pos] = (di_limb_t)(sum & DI_LIMB_MAX);
1863 carry = sum >> DI_LIMB_BITS;
1864 }
1865
1866 // Handle remaining carry
1867 if (carry > 0 && i + b->limb_count < result_capacity) {
1868 result->limbs[i + b->limb_count] = (di_limb_t)carry;
1869 }
1870 }
1871
1872 di_normalize(result);
1873 return result;
1874}
1875
1876// Big integer multiplication by int32
1877DI_IMPL di_int di_mul_i32(di_int a, int32_t b) {
1878 DI_ASSERT(a && "di_mul_i32: operand cannot be NULL");
1879
1880 di_int b_big = di_from_int32(b);
1881 di_int result = di_mul(a, b_big);
1882 di_release(&b_big);
1883 return result;
1884}
1885
1886// Big integer division - returns quotient
1888 DI_ASSERT(a != NULL && "di_div: dividend cannot be NULL");
1889 DI_ASSERT(b != NULL && "di_div: divisor cannot be NULL");
1890 DI_ASSERT(!di_is_zero(b) && "di_div: division by zero");
1891
1892 // Special cases
1893 if (di_is_zero(a)) return di_zero();
1894 if (di_eq(a, b)) return di_one();
1895
1896 // Compare absolute values
1897 di_int abs_a = di_abs(a);
1898 di_int abs_b = di_abs(b);
1899
1900 if (di_lt(abs_a, abs_b)) {
1901 di_release(&abs_a);
1902 di_release(&abs_b);
1903 return di_zero();
1904 }
1905
1906 // Proper long division algorithm for efficiency
1907 size_t dividend_limbs = abs_a->limb_count;
1908 size_t divisor_limbs = abs_b->limb_count;
1909
1910 // For single limb divisor, use optimized single-limb division
1911 if (divisor_limbs == 1) {
1912 di_limb_t divisor_limb = abs_b->limbs[0];
1913 struct di_int_internal* quotient = di_alloc(dividend_limbs);
1914 if (!quotient) {
1915 di_release(&abs_a);
1916 di_release(&abs_b);
1917 return NULL;
1918 }
1919
1920 quotient->limb_count = dividend_limbs;
1921 di_dlimb_t remainder = 0;
1922
1923 // Divide from most significant to least significant limb
1924 for (int i = (int)dividend_limbs - 1; i >= 0; i--) {
1925 di_dlimb_t temp = remainder * ((di_dlimb_t)DI_LIMB_MAX + 1) + abs_a->limbs[i];
1926 quotient->limbs[i] = (di_limb_t)(temp / divisor_limb);
1927 remainder = temp % divisor_limb;
1928 }
1929
1930 di_normalize(quotient);
1931
1932 // Set result sign and apply floor division semantics
1933 bool result_negative = (a->is_negative != b->is_negative);
1934
1935 // For floor division: if result would be negative and there's a remainder,
1936 // we need to add 1 to the quotient magnitude (going more negative)
1937 if (result_negative && remainder > 0 && quotient->limb_count > 0) {
1938 // Add 1 to quotient magnitude for floor division
1939 di_int one = di_one();
1940 di_int adjusted_quotient = di_add(quotient, one);
1941 di_release(&quotient);
1942 di_release(&one);
1943 quotient = adjusted_quotient;
1944 quotient->is_negative = true;
1945 } else if (result_negative && quotient->limb_count > 0) {
1946 quotient->is_negative = true;
1947 }
1948
1949 di_release(&abs_a);
1950 di_release(&abs_b);
1951 return quotient;
1952 }
1953
1954 // For multi-limb division, fall back to binary long division (more efficient than repeated subtraction)
1955 di_int quotient = di_zero();
1956 di_int remainder = di_zero();
1957
1958 // Process bits from most significant to least significant
1959 for (int limb_idx = (int)dividend_limbs - 1; limb_idx >= 0; limb_idx--) {
1960 for (int bit = DI_LIMB_BITS - 1; bit >= 0; bit--) {
1961 // Shift remainder left by 1
1962 di_int temp_remainder = di_shift_left(remainder, 1);
1963 di_release(&remainder);
1964 remainder = temp_remainder;
1965
1966 // Add current bit of dividend to remainder
1967 if (abs_a->limbs[limb_idx] & ((di_limb_t)1 << bit)) {
1968 di_int temp = di_add_i32(remainder, 1);
1969 di_release(&remainder);
1970 remainder = temp;
1971 }
1972
1973 // Shift quotient left by 1
1974 di_int temp_quotient = di_shift_left(quotient, 1);
1975 di_release(&quotient);
1976 quotient = temp_quotient;
1977
1978 // If remainder >= divisor, subtract divisor and set bit in quotient
1979 if (di_ge(remainder, abs_b)) {
1980 di_int temp_remainder = di_sub(remainder, abs_b);
1981 di_int temp_quotient = di_add_i32(quotient, 1);
1982 di_release(&remainder);
1983 di_release(&quotient);
1984 remainder = temp_remainder;
1985 quotient = temp_quotient;
1986 }
1987
1988 if (!remainder || !quotient) {
1989 di_release(&abs_a);
1990 di_release(&abs_b);
1991 di_release(&remainder);
1992 di_release(&quotient);
1993 return NULL;
1994 }
1995 }
1996 }
1997
1998 // Implement floor division (Python-style)
1999 bool result_negative = (a->is_negative != b->is_negative);
2000
2001 // For floor division: if result would be negative and there's a remainder,
2002 // we need to add 1 to the magnitude of the quotient (since we're going more negative)
2003 if (result_negative && !di_is_zero(remainder) && quotient->limb_count > 0) {
2004 // Add 1 to quotient magnitude for floor division
2005 di_int one = di_one();
2006 di_int adjusted_quotient = di_add(quotient, one);
2007 di_release(&quotient);
2008 di_release(&one);
2009 quotient = adjusted_quotient;
2010 }
2011
2012 // Set the sign
2013 if (result_negative && quotient->limb_count > 0) {
2014 quotient->is_negative = true;
2015 }
2016
2017 di_release(&abs_a);
2018 di_release(&abs_b);
2019 di_release(&remainder);
2020
2021 return quotient;
2022}
2023
2024// Big integer modulo - proper arbitrary precision implementation
2026 DI_ASSERT(a != NULL && "di_mod: dividend cannot be NULL");
2027 DI_ASSERT(b != NULL && "di_mod: divisor cannot be NULL");
2028 DI_ASSERT(!di_is_zero(b) && "di_mod: modulo by zero");
2029
2030 // Special cases
2031 if (di_is_zero(a)) return di_zero(); // 0 % b = 0
2032 if (di_eq(a, b)) return di_zero(); // a % a = 0
2033
2034 // For floor modulo: remainder = a - (floor(a/b) * b)
2035 // This ensures the remainder has the same sign as the divisor
2036 di_int quotient = di_div(a, b); // Use floor division
2037 di_int product = di_mul(quotient, b);
2038 di_int remainder = di_sub(a, product);
2039
2040 di_release(&quotient);
2041 di_release(&product);
2042
2043 return remainder;
2044}
2045
2046// Big integer absolute value
2048 DI_ASSERT(a && "di_abs: operand cannot be NULL");
2049
2050 // If already positive or zero, just return a copy
2051 if (!a->is_negative) {
2052 return di_copy(a);
2053 }
2054
2055 // Create a positive copy of the negative number
2056 di_int result = di_copy(a);
2057 if (result && result->limb_count > 0) {
2058 result->is_negative = false;
2059 }
2060 return result;
2061}
2062
2063// Bitwise operations
2065 DI_ASSERT(a && "di_and: first operand cannot be NULL");
2066 DI_ASSERT(b && "di_and: second operand cannot be NULL");
2067
2068 size_t max_limbs = (a->limb_count > b->limb_count) ? a->limb_count : b->limb_count;
2069 struct di_int_internal* result = di_alloc(max_limbs);
2070 DI_ASSERT(result && "allocation failed");
2071
2072 // AND operation on limbs
2073 for (size_t i = 0; i < max_limbs; i++) {
2074 di_limb_t a_limb = (i < a->limb_count) ? a->limbs[i] : 0;
2075 di_limb_t b_limb = (i < b->limb_count) ? b->limbs[i] : 0;
2076 result->limbs[i] = a_limb & b_limb;
2077 }
2078 result->limb_count = max_limbs;
2079
2080 // Result is positive (bitwise operations on magnitudes)
2081 result->is_negative = false;
2082 di_normalize(result);
2083
2084 return result;
2085}
2086
2087DI_IMPL di_int di_or(di_int a, di_int b) {
2088 DI_ASSERT(a && "di_or: first operand cannot be NULL");
2089 DI_ASSERT(b && "di_or: second operand cannot be NULL");
2090
2091 size_t max_limbs = (a->limb_count > b->limb_count) ? a->limb_count : b->limb_count;
2092 struct di_int_internal* result = di_alloc(max_limbs);
2093 DI_ASSERT(result && "allocation failed");
2094
2095 // OR operation on limbs
2096 for (size_t i = 0; i < max_limbs; i++) {
2097 di_limb_t a_limb = (i < a->limb_count) ? a->limbs[i] : 0;
2098 di_limb_t b_limb = (i < b->limb_count) ? b->limbs[i] : 0;
2099 result->limbs[i] = a_limb | b_limb;
2100 }
2101 result->limb_count = max_limbs;
2102
2103 // Result is positive (bitwise operations on magnitudes)
2104 result->is_negative = false;
2105 di_normalize(result);
2106
2107 return result;
2108}
2109
2111 DI_ASSERT(a && "di_xor: first operand cannot be NULL");
2112 DI_ASSERT(b && "di_xor: second operand cannot be NULL");
2113
2114 size_t max_limbs = (a->limb_count > b->limb_count) ? a->limb_count : b->limb_count;
2115 struct di_int_internal* result = di_alloc(max_limbs);
2116 DI_ASSERT(result && "allocation failed");
2117
2118 // XOR operation on limbs
2119 for (size_t i = 0; i < max_limbs; i++) {
2120 di_limb_t a_limb = (i < a->limb_count) ? a->limbs[i] : 0;
2121 di_limb_t b_limb = (i < b->limb_count) ? b->limbs[i] : 0;
2122 result->limbs[i] = a_limb ^ b_limb;
2123 }
2124 result->limb_count = max_limbs;
2125
2126 // Result is positive (bitwise operations on magnitudes)
2127 result->is_negative = false;
2128 di_normalize(result);
2129
2130 return result;
2131}
2132
2134 DI_ASSERT(a && "di_not: operand cannot be NULL");
2135
2136 // For simplicity, NOT operation on fixed width (one limb beyond significant bits)
2137 size_t result_limbs = a->limb_count + 1;
2138 struct di_int_internal* result = di_alloc(result_limbs);
2139 DI_ASSERT(result && "di_not: allocation failed");
2140
2141 // NOT operation on limbs
2142 for (size_t i = 0; i < a->limb_count; i++) {
2143 result->limbs[i] = ~a->limbs[i];
2144 }
2145 result->limbs[a->limb_count] = ~((di_limb_t)0); // Set high limb to all 1s
2146 result->limb_count = result_limbs;
2147
2148 // Result is positive (bitwise operations on magnitudes)
2149 result->is_negative = false;
2150 di_normalize(result);
2151
2152 return result;
2153}
2154
2155DI_IMPL di_int di_shift_left(di_int a, size_t bits) {
2156 DI_ASSERT(a && "di_shift_left: operand cannot be NULL");
2157 if (bits == 0) return di_copy(a);
2158
2159 size_t limb_shift = bits / DI_LIMB_BITS;
2160 size_t bit_shift = bits % DI_LIMB_BITS;
2161
2162 size_t new_limb_count = a->limb_count + limb_shift + (bit_shift > 0 ? 1 : 0);
2163 struct di_int_internal* result = di_alloc(new_limb_count);
2164 DI_ASSERT(result && "allocation failed");
2165
2166 // Clear the result limbs
2167 for (size_t i = 0; i < new_limb_count; i++) {
2168 result->limbs[i] = 0;
2169 }
2170
2171 // Copy and shift limbs
2172 if (bit_shift == 0) {
2173 // Simple limb shift
2174 for (size_t i = 0; i < a->limb_count; i++) {
2175 result->limbs[i + limb_shift] = a->limbs[i];
2176 }
2177 } else {
2178 // Bit shift within limbs
2179 di_limb_t carry = 0;
2180 for (size_t i = 0; i < a->limb_count; i++) {
2181 di_limb_t shifted = (a->limbs[i] << bit_shift) | carry;
2182 carry = a->limbs[i] >> (DI_LIMB_BITS - bit_shift);
2183 result->limbs[i + limb_shift] = shifted;
2184 }
2185 if (carry > 0) {
2186 result->limbs[a->limb_count + limb_shift] = carry;
2187 }
2188 }
2189
2190 result->limb_count = new_limb_count;
2191 result->is_negative = a->is_negative;
2192 di_normalize(result);
2193
2194 return result;
2195}
2196
2197DI_IMPL di_int di_shift_right(di_int a, size_t bits) {
2198 DI_ASSERT(a && "di_shift_right: operand cannot be NULL");
2199 if (bits == 0) return di_copy(a);
2200
2201 size_t limb_shift = bits / DI_LIMB_BITS;
2202 size_t bit_shift = bits % DI_LIMB_BITS;
2203
2204 // If shifting more limbs than we have, result is zero
2205 if (limb_shift >= a->limb_count) {
2206 return di_zero();
2207 }
2208
2209 size_t new_limb_count = a->limb_count - limb_shift;
2210 struct di_int_internal* result = di_alloc(new_limb_count);
2211 DI_ASSERT(result && "allocation failed");
2212
2213 if (bit_shift == 0) {
2214 // Simple limb shift
2215 for (size_t i = 0; i < new_limb_count; i++) {
2216 result->limbs[i] = a->limbs[i + limb_shift];
2217 }
2218 } else {
2219 // Bit shift within limbs
2220 for (size_t i = 0; i < new_limb_count; i++) {
2221 di_limb_t current = a->limbs[i + limb_shift];
2222 di_limb_t next = (i + limb_shift + 1 < a->limb_count) ?
2223 a->limbs[i + limb_shift + 1] : 0;
2224 result->limbs[i] = (current >> bit_shift) |
2225 (next << (DI_LIMB_BITS - bit_shift));
2226 }
2227 }
2228
2229 result->limb_count = new_limb_count;
2230 result->is_negative = a->is_negative;
2231 di_normalize(result);
2232
2233 return result;
2234}
2235
2236// GCD using Euclidean algorithm
2238 DI_ASSERT(a && "di_gcd: first operand cannot be NULL");
2239 DI_ASSERT(b && "di_gcd: second operand cannot be NULL");
2240
2241 di_int abs_a = di_abs(a);
2242 di_int abs_b = di_abs(b);
2243
2244 if (di_is_zero(abs_a)) {
2245 di_release(&abs_a);
2246 return abs_b;
2247 }
2248 if (di_is_zero(abs_b)) {
2249 di_release(&abs_b);
2250 return abs_a;
2251 }
2252
2253 // Euclidean algorithm: gcd(a,b) = gcd(b, a mod b)
2254 while (!di_is_zero(abs_b)) {
2255 di_int remainder = di_mod(abs_a, abs_b);
2256 if (!remainder) {
2257 di_release(&abs_a);
2258 di_release(&abs_b);
2259 return NULL;
2260 }
2261
2262 di_release(&abs_a);
2263 abs_a = abs_b;
2264 abs_b = remainder;
2265 }
2266
2267 di_release(&abs_b);
2268 return abs_a;
2269}
2270
2271// LCM using the identity: lcm(a,b) = |a*b| / gcd(a,b)
2273 DI_ASSERT(a && "di_lcm: first operand cannot be NULL");
2274 DI_ASSERT(b && "di_lcm: second operand cannot be NULL");
2275 if (di_is_zero(a) || di_is_zero(b)) return di_zero();
2276
2277 di_int gcd = di_gcd(a, b);
2278 DI_ASSERT(gcd && "di_lcm: gcd allocation failed");
2279
2280 di_int product = di_mul(a, b);
2281 if (!product) {
2282 di_release(&gcd);
2283 return NULL;
2284 }
2285
2286 di_int abs_product = di_abs(product);
2287 di_release(&product);
2288 if (!abs_product) {
2289 di_release(&gcd);
2290 return NULL;
2291 }
2292
2293 di_int result = di_div(abs_product, gcd);
2294 di_release(&abs_product);
2295 di_release(&gcd);
2296
2297 return result;
2298}
2299
2300// Simple integer square root using Newton's method
2302 DI_ASSERT(n && "di_sqrt: operand cannot be NULL");
2303 DI_ASSERT(!di_is_negative(n) && "di_sqrt: square root of negative number");
2304 if (di_is_zero(n)) return di_zero();
2305
2306 di_int one = di_one();
2307 if (di_eq(n, one)) {
2308 di_release(&one);
2309 return di_one();
2310 }
2311
2312 // Initial guess: x = n / 2
2313 di_int two = di_from_int32(2);
2314 di_int x = di_div(n, two);
2315 if (!x) {
2316 di_release(&one);
2317 di_release(&two);
2318 return NULL;
2319 }
2320
2321 // Newton's method: x_new = (x + n/x) / 2
2322 for (int iterations = 0; iterations < 100; iterations++) { // Limit iterations
2323 di_int quotient = di_div(n, x);
2324 if (!quotient) break;
2325
2326 di_int sum = di_add(x, quotient);
2327 di_release(&quotient);
2328 if (!sum) break;
2329
2330 di_int x_new = di_div(sum, two);
2331 di_release(&sum);
2332 if (!x_new) break;
2333
2334 // Check for convergence
2335 if (di_ge(x_new, x)) {
2336 di_release(&x_new);
2337 break;
2338 }
2339
2340 di_release(&x);
2341 x = x_new;
2342 }
2343
2344 di_release(&one);
2345 di_release(&two);
2346 return x;
2347}
2348
2349// Factorial function
2350DI_IMPL di_int di_factorial(uint32_t n) {
2351 if (n <= 1) return di_one();
2352
2353 di_int result = di_one();
2354 DI_ASSERT(result && "di_factorial: allocation failed");
2355
2356 for (uint32_t i = 2; i <= n; i++) {
2357 di_int i_big = di_from_uint32(i);
2358 if (!i_big) {
2359 di_release(&result);
2360 return NULL;
2361 }
2362
2363 di_int new_result = di_mul(result, i_big);
2364 di_release(&i_big);
2365 di_release(&result);
2366
2367 DI_ASSERT(new_result && "di_factorial: allocation failed");
2368 result = new_result;
2369 }
2370
2371 return result;
2372}
2373
2374// Modular exponentiation: (base^exp) mod mod
2375// Uses binary exponentiation for efficiency
2376DI_IMPL di_int di_mod_pow(di_int base, di_int exp, di_int mod) {
2377 DI_ASSERT(base && "di_mod_pow: base cannot be NULL");
2378 DI_ASSERT(exp && "di_mod_pow: exponent cannot be NULL");
2379 DI_ASSERT(mod && "di_mod_pow: modulus cannot be NULL");
2380 DI_ASSERT(!di_is_zero(mod) && "di_mod_pow: modulus cannot be zero");
2381 if (di_eq(mod, di_one())) return di_zero(); // x mod 1 = 0
2382
2383 if (di_is_zero(exp)) return di_one(); // base^0 = 1
2384 if (di_is_zero(base)) return di_zero(); // 0^exp = 0
2385
2386 di_int result = di_one();
2387 di_int base_mod = di_mod(base, mod); // Reduce base first
2388 di_int exp_copy = di_copy(exp);
2389
2390 if (!result || !base_mod || !exp_copy) {
2391 di_release(&result);
2392 di_release(&base_mod);
2393 di_release(&exp_copy);
2394 return NULL;
2395 }
2396
2397 // Binary exponentiation
2398 while (!di_is_zero(exp_copy)) {
2399 // If exp is odd, multiply result by base_mod
2400 di_int remainder = di_mod(exp_copy, di_from_int32(2));
2401 if (remainder && !di_is_zero(remainder)) {
2402 di_int temp = di_mul(result, base_mod);
2403 if (temp) {
2404 di_int new_result = di_mod(temp, mod);
2405 di_release(&temp);
2406 di_release(&result);
2407 result = new_result;
2408 }
2409 }
2410 di_release(&remainder);
2411
2412 // Square base_mod and divide exp by 2
2413 di_int base_squared = di_mul(base_mod, base_mod);
2414 if (base_squared) {
2415 di_int new_base = di_mod(base_squared, mod);
2416 di_release(&base_squared);
2417 di_release(&base_mod);
2418 base_mod = new_base;
2419 }
2420
2421 di_int two = di_from_int32(2);
2422 di_int new_exp = di_div(exp_copy, two);
2423 di_release(&two);
2424 di_release(&exp_copy);
2425 exp_copy = new_exp;
2426
2427 if (!result || !base_mod || !exp_copy) break;
2428 }
2429
2430 di_release(&base_mod);
2431 di_release(&exp_copy);
2432
2433 return result;
2434}
2435
2436// Simple primality test using trial division
2437DI_IMPL bool di_is_prime(di_int n, int certainty) {
2438 (void)certainty; // Unused in this simple implementation
2439
2440 DI_ASSERT(n && "di_is_prime: operand cannot be NULL");
2441 if (di_is_negative(n)) return false;
2442
2443 // Handle small cases
2444 di_int two = di_from_int32(2);
2445 di_int three = di_from_int32(3);
2446
2447 if (di_lt(n, two)) {
2448 di_release(&two);
2449 di_release(&three);
2450 return false;
2451 }
2452 if (di_eq(n, two) || di_eq(n, three)) {
2453 di_release(&two);
2454 di_release(&three);
2455 return true;
2456 }
2457
2458 // Check if even
2459 di_int remainder = di_mod(n, two);
2460 if (di_is_zero(remainder)) {
2461 di_release(&remainder);
2462 di_release(&two);
2463 di_release(&three);
2464 return false;
2465 }
2466 di_release(&remainder);
2467
2468 // Check odd divisors up to sqrt(n)
2469 di_int sqrt_n = di_sqrt(n);
2470 di_int i = di_copy(three);
2471
2472 while (di_le(i, sqrt_n)) {
2473 di_int remainder = di_mod(n, i);
2474 if (di_is_zero(remainder)) {
2475 di_release(&remainder);
2476 di_release(&two);
2477 di_release(&three);
2478 di_release(&sqrt_n);
2479 di_release(&i);
2480 return false; // Found a divisor
2481 }
2482 di_release(&remainder);
2483
2484 // i += 2 (check only odd numbers)
2485 di_int new_i = di_add(i, two);
2486 di_release(&i);
2487 i = new_i;
2488
2489 if (!i) break;
2490 }
2491
2492 di_release(&two);
2493 di_release(&three);
2494 di_release(&sqrt_n);
2495 di_release(&i);
2496
2497 return true;
2498}
2499
2500// Find next prime number >= n
2502 DI_ASSERT(n && "di_next_prime: operand cannot be NULL");
2503
2504 di_int candidate = di_copy(n);
2505 DI_ASSERT(candidate && "di_next_prime: allocation failed");
2506
2507 // If n is even, make it odd
2508 di_int two = di_from_int32(2);
2509 di_int remainder = di_mod(candidate, two);
2510 if (di_is_zero(remainder)) {
2511 di_int new_candidate = di_add(candidate, di_one());
2512 di_release(&candidate);
2513 candidate = new_candidate;
2514 }
2515 di_release(&remainder);
2516
2517 // Check odd numbers until we find a prime
2518 while (candidate && !di_is_prime(candidate, 10)) {
2519 di_int new_candidate = di_add(candidate, two);
2520 di_release(&candidate);
2521 candidate = new_candidate;
2522 }
2523
2524 di_release(&two);
2525 return candidate;
2526}
2527
2528// Simple random number generator (NOT cryptographically secure)
2529// This is a placeholder implementation - real applications should use
2530// a proper CSPRNG like /dev/urandom or Windows CryptoAPI
2531DI_IMPL di_int di_random(size_t bits) {
2532 if (bits == 0) return di_zero();
2533
2534 size_t limbs_needed = (bits + DI_LIMB_BITS - 1) / DI_LIMB_BITS;
2535 struct di_int_internal* result = di_alloc(limbs_needed);
2536 DI_ASSERT(result && "di_random: allocation failed");
2537
2538 // Use simple rand() - NOT suitable for cryptographic use
2539 for (size_t i = 0; i < limbs_needed; i++) {
2540 result->limbs[i] = 0;
2541 for (int j = 0; j < (int)(sizeof(di_limb_t)); j++) {
2542 result->limbs[i] |= ((di_limb_t)(rand() & 0xFF)) << (j * 8);
2543 }
2544 }
2545
2546 // Mask the high bits to get exactly 'bits' bits
2547 size_t high_bits = bits % DI_LIMB_BITS;
2548 if (high_bits > 0) {
2549 di_limb_t mask = (1UL << high_bits) - 1;
2550 result->limbs[limbs_needed - 1] &= mask;
2551 }
2552
2553 result->limb_count = limbs_needed;
2554 result->is_negative = false;
2555 di_normalize(result);
2556
2557 return result;
2558}
2559
2560// Random number in range [min, max)
2562 DI_ASSERT(min && "di_random_range: min cannot be NULL");
2563 DI_ASSERT(max && "di_random_range: max cannot be NULL");
2564 DI_ASSERT(di_lt(min, max) && "di_random_range: min must be less than max");
2565
2566 di_int range = di_sub(max, min);
2567 DI_ASSERT(range && "di_random_range: allocation failed");
2568
2569 // Get bit length of range to generate appropriate random number
2570 size_t range_bits = di_bit_length(range);
2571
2572 // Generate random numbers until we get one in range
2573 // (Rejection sampling to avoid bias)
2574 for (int attempts = 0; attempts < 100; attempts++) {
2575 di_int random = di_random(range_bits + 8); // Extra bits to reduce rejection
2576 if (!random) continue;
2577
2578 di_int mod_result = di_mod(random, range);
2579 di_release(&random);
2580
2581 if (mod_result) {
2582 di_int result = di_add(min, mod_result);
2583 di_release(&mod_result);
2584 di_release(&range);
2585 return result;
2586 }
2587 }
2588
2589 di_release(&range);
2590 return NULL; // Failed to generate
2591}
2592
2593// Calculate bit length of an arbitrary precision integer
2594DI_IMPL size_t di_bit_length(di_int big) {
2595 DI_ASSERT(big && "di_bit_length: operand cannot be NULL");
2596 if (big->limb_count == 0) return 0;
2597
2598 // Find the most significant limb
2599 size_t high_limb_idx = big->limb_count - 1;
2600 di_limb_t high_limb = big->limbs[high_limb_idx];
2601
2602 // Count bits in the high limb
2603 size_t high_limb_bits = 0;
2604 if (high_limb != 0) {
2605 di_limb_t temp = high_limb;
2606 while (temp > 0) {
2607 high_limb_bits++;
2608 temp >>= 1;
2609 }
2610 }
2611
2612 return high_limb_idx * DI_LIMB_BITS + high_limb_bits;
2613}
2614
2615// Count of limbs used
2616DI_IMPL size_t di_limb_count(di_int big) {
2617 DI_ASSERT(big && "di_limb_count: operand cannot be NULL");
2618 return big->limb_count;
2619}
2620
2621// Extended Euclidean Algorithm: finds gcd(a,b) and coefficients x,y such that ax + by = gcd(a,b)
2623 DI_ASSERT(a && "di_extended_gcd: first operand cannot be NULL");
2624 DI_ASSERT(b && "di_extended_gcd: second operand cannot be NULL");
2625 DI_ASSERT(x && "di_extended_gcd: x pointer cannot be NULL");
2626 DI_ASSERT(y && "di_extended_gcd: y pointer cannot be NULL");
2627
2628 // Initialize
2629 di_int old_r = di_abs(a);
2630 di_int r = di_abs(b);
2631 di_int old_s = di_one();
2632 di_int s = di_zero();
2633 di_int old_t = di_zero();
2634 di_int t = di_one();
2635
2636 if (!old_r || !r || !old_s || !s || !old_t || !t) {
2637 di_release(&old_r); di_release(&r);
2638 di_release(&old_s); di_release(&s);
2639 di_release(&old_t); di_release(&t);
2640 return NULL;
2641 }
2642
2643 while (!di_is_zero(r)) {
2644 di_int quotient = di_div(old_r, r);
2645 if (!quotient) break;
2646
2647 // (old_r, r) := (r, old_r - quotient * r)
2648 di_int temp1 = di_mul(quotient, r);
2649 di_int new_r = di_sub(old_r, temp1);
2650 di_release(&temp1);
2651 di_release(&old_r);
2652 old_r = r;
2653 r = new_r;
2654
2655 // (old_s, s) := (s, old_s - quotient * s)
2656 di_int temp2 = di_mul(quotient, s);
2657 di_int new_s = di_sub(old_s, temp2);
2658 di_release(&temp2);
2659 di_release(&old_s);
2660 old_s = s;
2661 s = new_s;
2662
2663 // (old_t, t) := (t, old_t - quotient * t)
2664 di_int temp3 = di_mul(quotient, t);
2665 di_int new_t = di_sub(old_t, temp3);
2666 di_release(&temp3);
2667 di_release(&quotient);
2668 di_release(&old_t);
2669 old_t = t;
2670 t = new_t;
2671
2672 if (!r || !s || !t) break;
2673 }
2674
2675 // Set output coefficients
2676 *x = old_s;
2677 *y = old_t;
2678
2679 di_release(&r);
2680 di_release(&s);
2681 di_release(&t);
2682
2683 return old_r; // This is gcd(a,b)
2684}
2685
2686#endif // DI_IMPLEMENTATION
2687
2688#endif // DYNAMIC_INT_H
struct di_int_internal * di_int
Integer handle for arbitrary precision integers.
di_int di_sqrt(di_int n)
Integer square root using Newton's method.
di_int di_mod_pow(di_int base, di_int exp, di_int mod)
Modular exponentiation: (base^exp) mod mod.
di_int di_lcm(di_int a, di_int b)
Least Common Multiple.
di_int di_factorial(uint32_t n)
Calculate factorial.
di_int di_gcd(di_int a, di_int b)
Greatest Common Divisor using Euclidean algorithm.
di_int di_extended_gcd(di_int a, di_int b, di_int *x, di_int *y)
Extended Euclidean Algorithm.
di_int di_abs(di_int a)
Get absolute value of an integer.
di_int di_mul_i32(di_int a, int32_t b)
Multiply an integer by a 32-bit signed integer.
di_int di_add_i32(di_int a, int32_t b)
Add an integer and a 32-bit signed integer.
di_int di_add(di_int a, di_int b)
Add two integers.
di_int di_pow(di_int base, uint32_t exp)
Raise integer to a power.
di_int di_sub(di_int a, di_int b)
Subtract two integers.
di_int di_div(di_int a, di_int b)
Divide two integers using floor division.
di_int di_mod(di_int a, di_int b)
Get remainder of integer division using floor modulo.
di_int di_sub_i32(di_int a, int32_t b)
Subtract a 32-bit signed integer from an integer.
di_int di_mul(di_int a, di_int b)
Multiply two integers.
di_int di_negate(di_int a)
Negate an integer (change sign)
di_int di_xor(di_int a, di_int b)
Bitwise XOR of two integers.
di_int di_shift_right(di_int a, size_t bits)
Right shift an integer by specified bits.
di_int di_shift_left(di_int a, size_t bits)
Left shift an integer by specified bits.
di_int di_or(di_int a, di_int b)
Bitwise OR of two integers.
di_int di_and(di_int a, di_int b)
Bitwise AND of two integers.
di_int di_not(di_int a)
Bitwise NOT (complement) of an integer.
bool di_is_zero(di_int big)
Test if integer is zero.
bool di_is_one(di_int big)
Test if integer equals one.
int di_compare(di_int a, di_int b)
Compare two integers.
bool di_lt(di_int a, di_int b)
Test if first integer is less than second.
bool di_is_negative(di_int big)
Test if integer is negative.
bool di_le(di_int a, di_int b)
Test if first integer is less than or equal to second.
bool di_gt(di_int a, di_int b)
Test if first integer is greater than second.
bool di_ge(di_int a, di_int b)
Test if first integer is greater than or equal to second.
bool di_is_positive(di_int big)
Test if integer is positive (> 0)
bool di_eq(di_int a, di_int b)
Test if two integers are equal.
bool di_to_uint64(di_int big, uint64_t *result)
Convert integer to 64-bit unsigned integer.
bool di_to_int32(di_int big, int32_t *result)
Convert integer to 32-bit signed integer.
double di_to_double(di_int big)
Convert integer to double precision floating point.
bool di_to_uint32(di_int big, uint32_t *result)
Convert integer to 32-bit unsigned integer.
char * di_to_string(di_int big, int base)
Convert integer to string representation.
bool di_to_int64(di_int big, int64_t *result)
Convert integer to 64-bit signed integer.
di_int di_from_uint32(uint32_t value)
Create a new integer from a 32-bit unsigned integer.
di_int di_copy(di_int big)
Create a deep copy of an integer.
di_int di_from_int32(int32_t value)
Create a new integer from a 32-bit signed integer.
di_int di_from_uint64(uint64_t value)
Create a new integer from a 64-bit unsigned integer.
di_int di_from_string(const char *str, int base)
Create a new integer from a string representation.
di_int di_from_int64(int64_t value)
Create a new integer from a 64-bit signed integer.
di_int di_zero(void)
Create a new integer with value zero.
di_int di_one(void)
Create a new integer with value one.
bool di_add_overflow_int32(int32_t a, int32_t b, int32_t *result)
Add two int32_t values with overflow detection.
bool di_multiply_overflow_int32(int32_t a, int32_t b, int32_t *result)
Multiply two int32_t values with overflow detection.
bool di_add_overflow_int64(int64_t a, int64_t b, int64_t *result)
Add two int64_t values with overflow detection.
bool di_multiply_overflow_int64(int64_t a, int64_t b, int64_t *result)
Multiply two int64_t values with overflow detection.
bool di_subtract_overflow_int64(int64_t a, int64_t b, int64_t *result)
Subtract two int64_t values with overflow detection.
bool di_subtract_overflow_int32(int32_t a, int32_t b, int32_t *result)
Subtract two int32_t values with overflow detection.
di_int di_next_prime(di_int n)
Find next prime number >= n.
bool di_is_prime(di_int n, int certainty)
Test if integer is prime (Miller-Rabin test)
di_int di_random(size_t bits)
Generate random integer with specified bit length.
di_int di_random_range(di_int min, di_int max)
Generate random integer in range [min, max)
size_t di_ref_count(di_int big)
Get current reference count of an integer.
di_int di_retain(di_int big)
Increment reference count and return the same integer.
void di_release(di_int *big)
Decrement reference count and free if zero.
size_t di_bit_length(di_int big)
Get bit length of integer (number of bits needed to represent)
size_t di_limb_count(di_int big)
Get number of limbs used by integer.
bool di_reserve(di_int big, size_t capacity)
Reserve capacity for an integer (performance optimization)