58#define DI_MALLOC malloc
62#define DI_REALLOC realloc
70#define DI_ASSERT assert
74#define DI_LIMB_BITS 32
87typedef uint32_t di_limb_t;
88typedef uint64_t di_dlimb_t;
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
95#error "DI_LIMB_BITS must be 16 or 32"
1010#ifdef DI_IMPLEMENTATION
1019struct di_int_internal {
1023 size_t limb_capacity;
1028static void di_resize_internal(
struct di_int_internal* big,
size_t new_capacity);
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");
1037 big->limb_count = 0;
1038 big->limb_capacity = initial_capacity;
1039 big->is_negative =
false;
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);
1052static void di_normalize(
struct di_int_internal* big) {
1054 while (big->limb_count > 0 && big->limbs[big->limb_count - 1] == 0) {
1059 if (big->limb_count == 0) {
1060 big->is_negative =
false;
1065 DI_ASSERT(big &&
"di_reserve: operand cannot be NULL");
1067 di_resize_internal(big, capacity);
1071static void di_resize_internal(
struct di_int_internal* big,
size_t new_capacity) {
1072 if (new_capacity <= big->limb_capacity)
return;
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");
1078 memset(new_limbs + big->limb_capacity, 0,
sizeof(di_limb_t) * (new_capacity - big->limb_capacity));
1080 big->limbs = new_limbs;
1081 big->limb_capacity = new_capacity;
1087 struct di_int_internal* big = di_alloc(1);
1088 DI_ASSERT(big &&
"di_from_int32: allocation failed");
1091 big->is_negative =
true;
1093 if (value == INT32_MIN) {
1094 big->limbs[0] = (di_limb_t)INT32_MAX + 1;
1096 big->limbs[0] = (di_limb_t)(-value);
1099 big->limbs[0] = (di_limb_t)value;
1101 big->limb_count = (value != 0) ? 1 : 0;
1107 struct di_int_internal* big = di_alloc(2);
1108 DI_ASSERT(big &&
"di_from_int64: allocation failed");
1111 big->is_negative =
true;
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);
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);
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);
1128 big->limb_count = 2;
1135 struct di_int_internal* big = di_alloc(1);
1136 DI_ASSERT(big &&
"di_from_uint32: allocation failed");
1138 big->limbs[0] = value;
1139 big->limb_count = (value != 0) ? 1 : 0;
1140 big->is_negative =
false;
1146 struct di_int_internal* big = di_alloc(2);
1147 DI_ASSERT(big &&
"di_from_uint64: allocation failed");
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;
1167 DI_ASSERT(big &&
"di_copy: operand cannot be NULL");
1169 struct di_int_internal* copy = di_alloc(big->limb_capacity);
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);
1181 DI_ASSERT(str &&
"di_from_string: string cannot be NULL");
1182 DI_ASSERT(base >= 2 && base <= 36 &&
"di_from_string: invalid base");
1185 while (*str ==
' ' || *str ==
'\t' || *str ==
'\n' || *str ==
'\r') str++;
1186 DI_ASSERT(*str !=
'\0' &&
"di_from_string: empty string");
1189 bool is_negative =
false;
1193 }
else if (*str ==
'+') {
1198 while (*str ==
'0') str++;
1199 if (*str ==
'\0')
return di_zero();
1202 const char* p = str;
1203 size_t digit_count = 0;
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;
1217 if (digit_val >= base)
break;
1222 if (digit_count == 0)
return NULL;
1226 size_t capacity = (digit_count + 7) / 8 + 1;
1227 if (capacity < 1) capacity = 1;
1229 struct di_int_internal* result = di_alloc(capacity);
1230 DI_ASSERT(result &&
"di_from_string: allocation failed");
1234 DI_ASSERT(base_big &&
"di_from_string: base allocation failed");
1237 for (
size_t i = 0; i < digit_count; i++) {
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;
1252 DI_ASSERT(temp &&
"di_from_string: multiplication allocation failed");
1255 DI_ASSERT(digit_big &&
"di_from_string: digit allocation failed");
1261 DI_ASSERT(new_result &&
"di_from_string: addition allocation failed");
1264 result = new_result;
1270 if (is_negative && result->limb_count > 0) {
1271 result->is_negative =
true;
1280 DI_ASSERT(big &&
"di_retain: operand cannot be NULL");
1286 if (!big || !*big)
return;
1288 struct di_int_internal* b = *big;
1289 if (--b->ref_count == 0) {
1299 DI_ASSERT(big &&
"di_ref_count: operand cannot be NULL");
1300 return big->ref_count;
1306 DI_ASSERT(a &&
"di_compare: first operand cannot be NULL");
1307 DI_ASSERT(b &&
"di_compare: second operand cannot be NULL");
1310 if (a->is_negative != b->is_negative) {
1311 return a->is_negative ? -1 : 1;
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;
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;
1325 if (a->limbs[i-1] < b->limbs[i-1]) {
1326 return a->is_negative ? 1 : -1;
1354 DI_ASSERT(big &&
"di_is_zero: operand cannot be NULL");
1355 return big->limb_count == 0;
1359 DI_ASSERT(big &&
"di_is_negative: operand cannot be NULL");
1360 return big->is_negative && big->limb_count > 0;
1364 DI_ASSERT(big &&
"di_is_positive: operand cannot be NULL");
1365 return !big->is_negative && big->limb_count > 0;
1369 DI_ASSERT(big &&
"di_is_one: operand cannot be NULL");
1370 if (big->is_negative || big->limb_count != 1) {
1373 return big->limbs[0] == 1;
1379 DI_ASSERT(big &&
"di_to_int32: integer cannot be NULL");
1380 DI_ASSERT(result &&
"di_to_int32: result pointer cannot be NULL");
1382 if (big->limb_count == 0) {
1387 if (big->limb_count > 1)
return false;
1389 di_limb_t val = big->limbs[0];
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;
1396 *result = -(int32_t)val;
1399 if (val > INT32_MAX)
return false;
1400 *result = (int32_t)val;
1407 DI_ASSERT(big &&
"di_to_int64: integer cannot be NULL");
1408 DI_ASSERT(result &&
"di_to_int64: result pointer cannot be NULL");
1410 if (big->limb_count == 0) {
1415 if (big->limb_count > 2)
return false;
1417 uint64_t val = big->limbs[0];
1418 if (big->limb_count == 2) {
1419 val |= ((uint64_t)big->limbs[1] << DI_LIMB_BITS);
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;
1427 *result = -(int64_t)val;
1430 if (val > INT64_MAX)
return false;
1431 *result = (int64_t)val;
1438 DI_ASSERT(big &&
"di_to_uint32: integer cannot be NULL");
1439 DI_ASSERT(result &&
"di_to_uint32: result pointer cannot be NULL");
1441 if (big->limb_count == 0) {
1447 if (big->is_negative)
return false;
1450 if (big->limb_count > 1) {
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;
1458 if (
sizeof(di_limb_t) >
sizeof(uint32_t) && big->limbs[0] > UINT32_MAX) {
1461 *result = (uint32_t)big->limbs[0];
1468 DI_ASSERT(big &&
"di_to_uint64: integer cannot be NULL");
1469 DI_ASSERT(result &&
"di_to_uint64: result pointer cannot be NULL");
1471 if (big->limb_count == 0) {
1477 if (big->is_negative)
return false;
1480 if (big->limb_count > 2)
return false;
1482 uint64_t val = big->limbs[0];
1483 if (big->limb_count == 2) {
1484 val |= ((uint64_t)big->limbs[1] << DI_LIMB_BITS);
1492 DI_ASSERT(big &&
"di_to_double: operand cannot be NULL");
1493 if (big->limb_count == 0)
return 0.0;
1495 double result = 0.0;
1498 for (
size_t i = 0; i < big->limb_count; i++) {
1499 result += big->limbs[i] * base;
1500 base *= (double)(DI_LIMB_MAX + 1ULL);
1503 return big->is_negative ? -result : result;
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;
1512 for (
size_t i = a->limb_count; i > 0; i--) {
1514 if (a->limbs[idx] > b->limbs[idx])
return 1;
1515 if (a->limbs[idx] < b->limbs[idx])
return -1;
1524 DI_ASSERT(a != NULL &&
"di_add: first operand cannot be NULL");
1525 DI_ASSERT(b != NULL &&
"di_add: second operand cannot be NULL");
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
1532 DI_ASSERT(result &&
"di_add: allocation failed");
1534 result->is_negative = a->is_negative;
1536 di_dlimb_t carry = 0;
1537 size_t max_limbs = a->limb_count > b->limb_count ? a->limb_count : b->limb_count;
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];
1544 result->limbs[i] = (di_limb_t)(sum & DI_LIMB_MAX);
1545 carry = sum >> DI_LIMB_BITS;
1549 result->limbs[max_limbs] = (di_limb_t)carry;
1550 result->limb_count = max_limbs + 1;
1552 result->limb_count = max_limbs;
1555 di_normalize(result);
1561 int cmp = di_compare_magnitude(a, b);
1563 struct di_int_internal* larger = (cmp >= 0) ? a : b;
1564 struct di_int_internal* smaller = (cmp >= 0) ? b : a;
1569 bool result_negative = (cmp >= 0) ? a->is_negative : b->is_negative;
1572 struct di_int_internal* result = di_alloc(larger->limb_count);
1573 DI_ASSERT(result &&
"di_sub: allocation failed");
1575 result->is_negative = result_negative;
1576 result->limb_count = larger->limb_count;
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;
1584 int64_t signed_diff = (int64_t)a_limb - (int64_t)b_limb - (int64_t)borrow;
1587 if (signed_diff < 0) {
1588 diff = (di_dlimb_t)(signed_diff + (1ULL << DI_LIMB_BITS));
1591 diff = (di_dlimb_t)signed_diff;
1595 result->limbs[i] = (di_limb_t)diff;
1598 di_normalize(result);
1603 DI_ASSERT(a &&
"di_add_i32: operand cannot be NULL");
1607 DI_ASSERT(b_big &&
"di_add_i32: allocation failed");
1615 DI_ASSERT(a != NULL &&
"di_sub: first operand cannot be NULL");
1616 DI_ASSERT(b != NULL &&
"di_sub: second operand cannot be NULL");
1620 DI_ASSERT(neg_b &&
"di_sub: allocation failed");
1628 DI_ASSERT(a &&
"di_sub_i32: operand cannot be NULL");
1632 DI_ASSERT(b_big &&
"di_sub_i32: allocation failed");
1640 DI_ASSERT(a &&
"di_negate: operand cannot be NULL");
1643 if (result && result->limb_count > 0) {
1644 result->is_negative = !result->is_negative;
1651 DI_ASSERT(big &&
"di_to_string: operand cannot be NULL");
1652 DI_ASSERT(base >= 2 && base <= 36 &&
"di_to_string: invalid base");
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");
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");
1672 char* digits = (
char*)DI_MALLOC(max_digits);
1673 DI_ASSERT(digits &&
"di_to_string: digits allocation failed");
1675 size_t digit_count = 0;
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;
1697 digits[digit_count++] =
'0' + (char)remainder;
1700 while (work->limb_count > 0 && work->limbs[work->limb_count - 1] == 0) {
1707 if (big->is_negative) {
1708 buffer[pos++] =
'-';
1711 for (
size_t i = digit_count; i > 0; i--) {
1712 buffer[pos++] = digits[i - 1];
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) {
1733 *result = (int32_t)sum;
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) {
1743 *result = (int32_t)diff;
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) {
1753 *result = (int32_t)prod;
1758 DI_ASSERT(result &&
"di_add_overflow_int64: result pointer cannot be NULL");
1760 if (b > 0 && a > INT64_MAX - b)
return false;
1761 if (b < 0 && a < INT64_MIN - b)
return false;
1767 DI_ASSERT(result &&
"di_subtract_overflow_int64: result pointer cannot be NULL");
1769 if (b < 0 && a > INT64_MAX + b)
return false;
1770 if (b > 0 && a < INT64_MIN + b)
return false;
1776 DI_ASSERT(result &&
"di_multiply_overflow_int64: result pointer cannot be NULL");
1778 if (a == 0 || b == 0) {
1786 if (a > INT64_MAX / b)
return false;
1788 if (b < INT64_MIN / a)
return false;
1792 if (a < INT64_MIN / b)
return false;
1794 if (a != 0 && b < INT64_MAX / a)
return false;
1804 DI_ASSERT(a != NULL &&
"di_mul: first operand cannot be NULL");
1805 DI_ASSERT(b != NULL &&
"di_mul: second operand cannot be NULL");
1808 if (a->limb_count == 0 || b->limb_count == 0) {
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);
1817 if (product <= DI_LIMB_MAX) {
1820 if (result && result_negative && product > 0) {
1821 result->is_negative =
true;
1826 struct di_int_internal* result = di_alloc(2);
1827 DI_ASSERT(result &&
"di_mul: allocation failed");
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);
1834 di_normalize(result);
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");
1845 result->is_negative = result_negative;
1846 result->limb_count = result_capacity;
1849 for (
size_t i = 0; i < result_capacity; i++) {
1850 result->limbs[i] = 0;
1854 for (
size_t i = 0; i < a->limb_count; i++) {
1855 di_dlimb_t carry = 0;
1857 for (
size_t j = 0; j < b->limb_count; 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;
1862 result->limbs[pos] = (di_limb_t)(sum & DI_LIMB_MAX);
1863 carry = sum >> DI_LIMB_BITS;
1867 if (carry > 0 && i + b->limb_count < result_capacity) {
1868 result->limbs[i + b->limb_count] = (di_limb_t)carry;
1872 di_normalize(result);
1878 DI_ASSERT(a &&
"di_mul_i32: operand cannot be NULL");
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");
1900 if (
di_lt(abs_a, abs_b)) {
1907 size_t dividend_limbs = abs_a->limb_count;
1908 size_t divisor_limbs = abs_b->limb_count;
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);
1920 quotient->limb_count = dividend_limbs;
1921 di_dlimb_t remainder = 0;
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;
1930 di_normalize(quotient);
1933 bool result_negative = (a->is_negative != b->is_negative);
1937 if (result_negative && remainder > 0 && quotient->limb_count > 0) {
1943 quotient = adjusted_quotient;
1944 quotient->is_negative =
true;
1945 }
else if (result_negative && quotient->limb_count > 0) {
1946 quotient->is_negative =
true;
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--) {
1964 remainder = temp_remainder;
1967 if (abs_a->limbs[limb_idx] & ((di_limb_t)1 << bit)) {
1976 quotient = temp_quotient;
1979 if (
di_ge(remainder, abs_b)) {
1984 remainder = temp_remainder;
1985 quotient = temp_quotient;
1988 if (!remainder || !quotient) {
1999 bool result_negative = (a->is_negative != b->is_negative);
2003 if (result_negative && !
di_is_zero(remainder) && quotient->limb_count > 0) {
2009 quotient = adjusted_quotient;
2013 if (result_negative && quotient->limb_count > 0) {
2014 quotient->is_negative =
true;
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");
2048 DI_ASSERT(a &&
"di_abs: operand cannot be NULL");
2051 if (!a->is_negative) {
2057 if (result && result->limb_count > 0) {
2058 result->is_negative =
false;
2065 DI_ASSERT(a &&
"di_and: first operand cannot be NULL");
2066 DI_ASSERT(b &&
"di_and: second operand cannot be NULL");
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");
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;
2078 result->limb_count = max_limbs;
2081 result->is_negative =
false;
2082 di_normalize(result);
2088 DI_ASSERT(a &&
"di_or: first operand cannot be NULL");
2089 DI_ASSERT(b &&
"di_or: second operand cannot be NULL");
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");
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;
2101 result->limb_count = max_limbs;
2104 result->is_negative =
false;
2105 di_normalize(result);
2111 DI_ASSERT(a &&
"di_xor: first operand cannot be NULL");
2112 DI_ASSERT(b &&
"di_xor: second operand cannot be NULL");
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");
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;
2124 result->limb_count = max_limbs;
2127 result->is_negative =
false;
2128 di_normalize(result);
2134 DI_ASSERT(a &&
"di_not: operand cannot be NULL");
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");
2142 for (
size_t i = 0; i < a->limb_count; i++) {
2143 result->limbs[i] = ~a->limbs[i];
2145 result->limbs[a->limb_count] = ~((di_limb_t)0);
2146 result->limb_count = result_limbs;
2149 result->is_negative =
false;
2150 di_normalize(result);
2156 DI_ASSERT(a &&
"di_shift_left: operand cannot be NULL");
2157 if (bits == 0)
return di_copy(a);
2159 size_t limb_shift = bits / DI_LIMB_BITS;
2160 size_t bit_shift = bits % DI_LIMB_BITS;
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");
2167 for (
size_t i = 0; i < new_limb_count; i++) {
2168 result->limbs[i] = 0;
2172 if (bit_shift == 0) {
2174 for (
size_t i = 0; i < a->limb_count; i++) {
2175 result->limbs[i + limb_shift] = a->limbs[i];
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;
2186 result->limbs[a->limb_count + limb_shift] = carry;
2190 result->limb_count = new_limb_count;
2191 result->is_negative = a->is_negative;
2192 di_normalize(result);
2198 DI_ASSERT(a &&
"di_shift_right: operand cannot be NULL");
2199 if (bits == 0)
return di_copy(a);
2201 size_t limb_shift = bits / DI_LIMB_BITS;
2202 size_t bit_shift = bits % DI_LIMB_BITS;
2205 if (limb_shift >= a->limb_count) {
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");
2213 if (bit_shift == 0) {
2215 for (
size_t i = 0; i < new_limb_count; i++) {
2216 result->limbs[i] = a->limbs[i + limb_shift];
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));
2229 result->limb_count = new_limb_count;
2230 result->is_negative = a->is_negative;
2231 di_normalize(result);
2238 DI_ASSERT(a &&
"di_gcd: first operand cannot be NULL");
2239 DI_ASSERT(b &&
"di_gcd: second operand cannot be NULL");
2273 DI_ASSERT(a &&
"di_lcm: first operand cannot be NULL");
2274 DI_ASSERT(b &&
"di_lcm: second operand cannot be NULL");
2278 DI_ASSERT(gcd &&
"di_lcm: gcd allocation failed");
2302 DI_ASSERT(n &&
"di_sqrt: operand cannot be NULL");
2303 DI_ASSERT(!
di_is_negative(n) &&
"di_sqrt: square root of negative number");
2307 if (
di_eq(n, one)) {
2322 for (
int iterations = 0; iterations < 100; iterations++) {
2324 if (!quotient)
break;
2335 if (
di_ge(x_new, x)) {
2351 if (n <= 1)
return di_one();
2354 DI_ASSERT(result &&
"di_factorial: allocation failed");
2356 for (uint32_t i = 2; i <= n; i++) {
2367 DI_ASSERT(new_result &&
"di_factorial: allocation failed");
2368 result = new_result;
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");
2390 if (!result || !base_mod || !exp_copy) {
2407 result = new_result;
2418 base_mod = new_base;
2427 if (!result || !base_mod || !exp_copy)
break;
2440 DI_ASSERT(n &&
"di_is_prime: operand cannot be NULL");
2447 if (
di_lt(n, two)) {
2472 while (
di_le(i, sqrt_n)) {
2502 DI_ASSERT(n &&
"di_next_prime: operand cannot be NULL");
2505 DI_ASSERT(candidate &&
"di_next_prime: allocation failed");
2513 candidate = new_candidate;
2518 while (candidate && !
di_is_prime(candidate, 10)) {
2521 candidate = new_candidate;
2532 if (bits == 0)
return di_zero();
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");
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);
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;
2553 result->limb_count = limbs_needed;
2554 result->is_negative =
false;
2555 di_normalize(result);
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");
2567 DI_ASSERT(range &&
"di_random_range: allocation failed");
2574 for (
int attempts = 0; attempts < 100; attempts++) {
2576 if (!random)
continue;
2595 DI_ASSERT(big &&
"di_bit_length: operand cannot be NULL");
2596 if (big->limb_count == 0)
return 0;
2599 size_t high_limb_idx = big->limb_count - 1;
2600 di_limb_t high_limb = big->limbs[high_limb_idx];
2603 size_t high_limb_bits = 0;
2604 if (high_limb != 0) {
2605 di_limb_t temp = high_limb;
2612 return high_limb_idx * DI_LIMB_BITS + high_limb_bits;
2617 DI_ASSERT(big &&
"di_limb_count: operand cannot be NULL");
2618 return big->limb_count;
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");
2636 if (!old_r || !r || !old_s || !s || !old_t || !t) {
2645 if (!quotient)
break;
2672 if (!r || !s || !t)
break;
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)