diff options
Diffstat (limited to 'prism/util/pm_integer.c')
-rw-r--r-- | prism/util/pm_integer.c | 61 |
1 files changed, 48 insertions, 13 deletions
diff --git a/prism/util/pm_integer.c b/prism/util/pm_integer.c index 0739662e98..5b0f34465c 100644 --- a/prism/util/pm_integer.c +++ b/prism/util/pm_integer.c @@ -48,7 +48,7 @@ big_add(pm_integer_t *destination, pm_integer_t *left, pm_integer_t *right, uint /** * Internal use for karatsuba_multiply. Calculates `a - b - c` with the given - * base. Assume a, b, c, a - b - c all to be poitive. + * base. Assume a, b, c, a - b - c all to be positive. * Return pm_integer_t with values allocated. Not normalized. */ static void @@ -135,12 +135,19 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t * } if (left_length * 2 <= right_length) { - uint32_t *values = (uint32_t*) xcalloc(left_length + right_length, sizeof(uint32_t)); + uint32_t *values = (uint32_t *) xcalloc(left_length + right_length, sizeof(uint32_t)); for (size_t start_offset = 0; start_offset < right_length; start_offset += left_length) { size_t end_offset = start_offset + left_length; if (end_offset > right_length) end_offset = right_length; + pm_integer_t sliced_left = { + .value = 0, + .length = left_length, + .values = left_values, + .negative = false + }; + pm_integer_t sliced_right = { .value = 0, .length = end_offset - start_offset, @@ -149,7 +156,7 @@ karatsuba_multiply(pm_integer_t *destination, pm_integer_t *left, pm_integer_t * }; pm_integer_t product; - karatsuba_multiply(&product, left, &sliced_right, base); + karatsuba_multiply(&product, &sliced_left, &sliced_right, base); uint32_t carry = 0; for (size_t index = 0; index < product.length; index++) { @@ -464,15 +471,18 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t * * has already been validated, as internal validation checks are not performed * here. */ -PRISM_EXPORTED_FUNCTION void +void pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *start, const uint8_t *end) { - // Ignore unary +. Unary + is parsed differently and will not end up here. + // Ignore unary +. Unary - is parsed differently and will not end up here. // Instead, it will modify the parsed integer later. if (*start == '+') start++; // Determine the multiplier from the base, and skip past any prefixes. uint32_t multiplier = 10; switch (base) { + case PM_INTEGER_BASE_DEFAULT: + while (*start == '0') start++; // 01 -> 1 + break; case PM_INTEGER_BASE_BINARY: start += 2; // 0b multiplier = 2; @@ -527,14 +537,6 @@ pm_integer_parse(pm_integer_t *integer, pm_integer_base_t base, const uint8_t *s } /** - * Return the memory size of the integer. - */ -size_t -pm_integer_memsize(const pm_integer_t *integer) { - return sizeof(pm_integer_t) + integer->length * sizeof(uint32_t); -} - -/** * Compare two integers. This function returns -1 if the left integer is less * than the right integer, 0 if they are equal, and 1 if the left integer is * greater than the right integer. @@ -566,6 +568,39 @@ pm_integer_compare(const pm_integer_t *left, const pm_integer_t *right) { } /** + * Reduce a ratio of integers to its simplest form. + */ +void pm_integers_reduce(pm_integer_t *numerator, pm_integer_t *denominator) { + // If either the numerator or denominator do not fit into a 32-bit integer, + // then this function is a no-op. In the future, we may consider reducing + // even the larger numbers, but for now we're going to keep it simple. + if ( + // If the numerator doesn't fit into a 32-bit integer, return early. + numerator->length != 0 || + // If the denominator doesn't fit into a 32-bit integer, return early. + denominator->length != 0 || + // If the numerator is 0, then return early. + numerator->value == 0 || + // If the denominator is 1, then return early. + denominator->value == 1 + ) return; + + // Find the greatest common divisor of the numerator and denominator. + uint32_t divisor = numerator->value; + uint32_t remainder = denominator->value; + + while (remainder != 0) { + uint32_t temporary = remainder; + remainder = divisor % remainder; + divisor = temporary; + } + + // Divide the numerator and denominator by the greatest common divisor. + numerator->value /= divisor; + denominator->value /= divisor; +} + +/** * Convert an integer to a decimal string. */ PRISM_EXPORTED_FUNCTION void |