45#ifndef DYNAMIC_FRACTION_H
46#define DYNAMIC_FRACTION_H
60#define DF_MALLOC malloc
68#define DF_ASSERT assert
542#ifdef DF_IMPLEMENTATION
553 DF_ASSERT(f &&
"df_alloc: memory allocation failed");
561static void df_reduce(
df_frac f) {
562 DF_ASSERT(f &&
"df_reduce: fraction cannot be NULL");
563 DF_ASSERT(f->
numerator &&
"df_reduce: numerator cannot be NULL");
564 DF_ASSERT(f->
denominator &&
"df_reduce: denominator cannot be NULL");
586static void df_normalize_sign(
df_frac f) {
587 DF_ASSERT(f &&
"df_normalize_sign: fraction cannot be NULL");
588 DF_ASSERT(f->
denominator &&
"df_normalize_sign: denominator cannot be NULL");
603 DF_ASSERT(
denominator != 0 &&
"df_from_ints: denominator cannot be zero");
606 DF_ASSERT(f &&
"df_from_ints: allocation failed");
618 df_normalize_sign(f);
625 DF_ASSERT(
numerator &&
"df_from_di: numerator cannot be NULL");
629 DF_ASSERT(f &&
"df_from_ints: allocation failed");
634 df_normalize_sign(f);
646 if (isnan(value) || isinf(value))
return NULL;
647 if (max_denominator <= 0) max_denominator = INT64_MAX;
650 bool negative = value < 0;
651 if (negative) value = -value;
654 int64_t h0 = 0, h1 = 1;
655 int64_t k0 = 1, k1 = 0;
658 while (k1 <= max_denominator) {
659 int64_t a = (int64_t)floor(x);
660 int64_t h2 = a * h1 + h0;
661 int64_t k2 = a * k1 + k0;
663 if (k2 > max_denominator)
break;
668 if (fabs(value - (
double)h1 / (
double)k1) < 1e-15)
break;
679 DF_ASSERT(f &&
"df_copy: fraction cannot be NULL");
690 DF_ASSERT(f &&
"df_retain: fraction cannot be NULL");
697 if (!f || !*f)
return;
700 if ((*f)->ref_count == 0) {
710 DF_ASSERT(a &&
"df_add: first operand cannot be NULL");
711 DF_ASSERT(b &&
"df_add: second operand cannot be NULL");
733 DF_ASSERT(a &&
"df_sub: first operand cannot be NULL");
734 DF_ASSERT(b &&
"df_sub: second operand cannot be NULL");
756 DF_ASSERT(a &&
"df_mul: first operand cannot be NULL");
757 DF_ASSERT(b &&
"df_mul: second operand cannot be NULL");
772 DF_ASSERT(a &&
"df_div: dividend cannot be NULL");
773 DF_ASSERT(b &&
"df_div: divisor cannot be NULL");
774 DF_ASSERT(!
df_is_zero(b) &&
"df_div: division by zero");
789 DF_ASSERT(f &&
"df_negate: operand cannot be NULL");
802 DF_ASSERT(f &&
"df_abs: operand cannot be NULL");
815 DF_ASSERT(f &&
"df_reciprocal: operand cannot be NULL");
816 DF_ASSERT(!
df_is_zero(f) &&
"df_reciprocal: reciprocal of zero");
828 DF_ASSERT(a &&
"df_cmp: first operand cannot be NULL");
829 DF_ASSERT(b &&
"df_cmp: second operand cannot be NULL");
875 DF_ASSERT(f &&
"df_is_zero: operand cannot be NULL");
881 DF_ASSERT(f &&
"df_is_one: operand cannot be NULL");
887 DF_ASSERT(f &&
"df_is_negative: operand cannot be NULL");
893 DF_ASSERT(f &&
"df_is_positive: operand cannot be NULL");
899 DF_ASSERT(f &&
"df_is_integer: operand cannot be NULL");
905 DF_ASSERT(f &&
"df_to_double: operand cannot be NULL");
915 DF_ASSERT(f &&
"df_to_int64: fraction cannot be NULL");
916 DF_ASSERT(result &&
"df_to_int64: result pointer cannot be NULL");
924 DF_ASSERT(f &&
"df_to_string: operand cannot be NULL");
927 DF_ASSERT(num_str &&
"df_to_string: numerator string conversion failed");
941 size_t len = strlen(num_str) + strlen(den_str) + 2;
942 char* result = (
char*)DF_MALLOC(len);
943 DF_ASSERT(result &&
"df_to_string: result allocation failed");
945 snprintf(result, len,
"%s/%s", num_str, den_str);
955 DF_ASSERT(str &&
"df_from_string: string cannot be NULL");
958 const char* slash = strchr(str,
'/');
963 DF_ASSERT(num &&
"df_from_string: numerator parsing failed");
975 size_t num_len = slash - str;
976 char* num_str = (
char*)DF_MALLOC(num_len + 1);
977 DF_ASSERT(num_str &&
"df_from_string: numerator string allocation failed");
979 strncpy(num_str, str, num_len);
980 num_str[num_len] =
'\0';
985 DF_ASSERT(num &&
"df_from_string: numerator parsing failed");
988 DF_ASSERT(den &&
"df_from_string: denominator parsing failed");
989 DF_ASSERT(!
di_is_zero(den) &&
"df_from_string: denominator cannot be zero");
1001 DF_ASSERT(f &&
"df_numerator: operand cannot be NULL");
1007 DF_ASSERT(f &&
"df_denominator: operand cannot be NULL");
1032 DF_ASSERT(base &&
"df_pow: base cannot be NULL");
1034 if (exponent == 0) {
1038 if (exponent == 1) {
1043 DF_ASSERT(exponent > 0 &&
"df_pow: zero to negative power is undefined");
1059 while (exponent > 0) {
1063 result = new_result;
1069 current_base = new_base;
1079 DF_ASSERT(f &&
"df_floor: operand cannot be NULL");
1097 DF_ASSERT(f &&
"df_ceil: operand cannot be NULL");
1119 DF_ASSERT(f &&
"df_trunc: operand cannot be NULL");
1136 DF_ASSERT(f &&
"df_round: operand cannot be NULL");
1147 if (
df_eq(abs_frac_part, half)) {
1160 if (whole_val % 2 == 0) {
1172 adjusted_whole =
di_sub(whole, one);
1174 adjusted_whole =
di_add(whole, one);
1211 DF_ASSERT(f &&
"df_sign: operand cannot be NULL");
1220 DF_ASSERT(a &&
"df_min: first operand cannot be NULL");
1221 DF_ASSERT(b &&
"df_min: second operand cannot be NULL");
1228 DF_ASSERT(a &&
"df_max: first operand cannot be NULL");
1229 DF_ASSERT(b &&
"df_max: second operand cannot be NULL");
1237 DF_ASSERT(f &&
"df_hash: operand cannot be NULL");
1241 uint64_t h1 = 0, h2 = 0;
1248 for (
const char* s = num_str; *s; s++) {
1249 h1 = h1 * 33 + (uint8_t)*s;
1251 for (
const char* s = den_str; *s; s++) {
1252 h2 = h2 * 33 + (uint8_t)*s;
1259 return h1 ^ (h2 << 1);
1264 DF_ASSERT(f &&
"df_fits_int32: operand cannot be NULL");
1273 DF_ASSERT(f &&
"df_fits_int64: operand cannot be NULL");
1282 DF_ASSERT(f &&
"df_fits_double: operand cannot be NULL");
1286 if (!isfinite(d))
return false;
1289 bool fits =
df_eq(f, converted);
1297 DF_ASSERT(f &&
"df_whole_part: operand cannot be NULL");
1316 DF_ASSERT(f &&
"df_fractional_part: operand cannot be NULL");
struct df_frac_internal * df_frac
Opaque pointer to a rational number.
Reference-counted arbitrary precision integer library.
struct di_int_internal * di_int
Integer handle for arbitrary precision integers.
di_int di_gcd(di_int a, di_int b)
Greatest Common Divisor using Euclidean algorithm.
di_int di_abs(di_int a)
Get absolute value of an integer.
di_int di_add(di_int a, di_int b)
Add two integers.
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_mul(di_int a, di_int b)
Multiply two integers.
di_int di_negate(di_int a)
Negate an integer (change sign)
df_frac df_add(df_frac a, df_frac b)
Add two fractions.
df_frac df_abs(df_frac f)
Get absolute value.
df_frac df_sub(df_frac a, df_frac b)
Subtract two fractions.
df_frac df_negate(df_frac f)
Negate a fraction.
df_frac df_div(df_frac a, df_frac b)
Divide two fractions.
df_frac df_mul(df_frac a, df_frac b)
Multiply two fractions.
df_frac df_reciprocal(df_frac f)
Get reciprocal (1/f)
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_is_negative(di_int big)
Test if integer is negative.
bool di_eq(di_int a, di_int b)
Test if two integers are equal.
bool df_gt(df_frac a, df_frac b)
Test greater than.
bool df_ne(df_frac a, df_frac b)
Test inequality.
bool df_eq(df_frac a, df_frac b)
Test equality.
bool df_le(df_frac a, df_frac b)
Test less than or equal.
bool df_ge(df_frac a, df_frac b)
Test greater than or equal.
int df_cmp(df_frac a, df_frac b)
Compare two fractions.
bool df_lt(df_frac a, df_frac b)
Test less than.
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.
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.
bool df_to_int64(df_frac f, int64_t *result)
Convert to int64_t if possible.
char * df_to_string(df_frac f)
Convert to string.
di_int df_denominator(df_frac f)
Get denominator as di_int.
di_int df_numerator(df_frac f)
Get numerator as di_int.
double df_to_double(df_frac f)
Convert to double.
df_frac df_from_string(const char *str)
Parse fraction from string.
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_one(void)
Create a new integer with value one.
df_frac df_pow(df_frac base, int64_t exponent)
Raise fraction to integer power.
df_frac df_max(df_frac a, df_frac b)
Maximum of two fractions.
uint64_t df_hash(df_frac f)
Hash function for fractions.
bool df_fits_int32(df_frac f)
Check if fraction fits in int32_t.
df_frac df_round(df_frac f)
Round to nearest integer.
di_int df_whole_part(df_frac f)
Get integer (whole) part of fraction.
df_frac df_min(df_frac a, df_frac b)
Minimum of two fractions.
df_frac df_floor(df_frac f)
Floor function - greatest integer ≤ f.
df_frac df_trunc(df_frac f)
Truncate towards zero.
df_frac df_fractional_part(df_frac f)
Get fractional part of fraction.
int df_sign(df_frac f)
Get sign of fraction.
df_frac df_ceil(df_frac f)
Ceiling function - smallest integer ≥ f.
bool df_fits_double(df_frac f)
Check if fraction fits in double without precision loss.
bool df_fits_int64(df_frac f)
Check if fraction fits in int64_t.
df_frac df_from_di(di_int numerator, di_int denominator)
Create a fraction from a di_int numerator and denominator.
df_frac df_retain(df_frac f)
Increase reference count.
void df_release(df_frac *f)
Decrease reference count and free if zero.
df_frac df_copy(df_frac f)
Create a copy of a fraction.
df_frac df_from_ints(int64_t numerator, int64_t denominator)
Create a fraction from numerator and denominator.
df_frac df_from_double(double value, int64_t max_denominator)
Create a fraction from a double.
df_frac df_from_int(int64_t value)
Create a fraction from an integer.
bool df_is_negative(df_frac f)
Test if fraction is negative.
bool df_is_integer(df_frac f)
Test if fraction is an integer.
bool df_is_positive(df_frac f)
Test if fraction is positive.
bool df_is_one(df_frac f)
Test if fraction is one.
bool df_is_zero(df_frac f)
Test if fraction is zero.
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.
df_frac df_one(void)
Create one fraction (1/1)
df_frac df_zero(void)
Create zero fraction (0/1)
df_frac df_neg_one(void)
Create negative one fraction (-1/1)
Internal structure for a rational number.