summaryrefslogtreecommitdiff
path: root/prism/util/pm_integer.c
diff options
context:
space:
mode:
Diffstat (limited to 'prism/util/pm_integer.c')
-rw-r--r--prism/util/pm_integer.c61
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