summaryrefslogtreecommitdiff
path: root/prism/util/pm_integer.c
diff options
context:
space:
mode:
authorKevin Newton <[email protected]>2024-05-08 15:32:24 -0400
committerKevin Newton <[email protected]>2024-05-21 14:27:46 -0400
commit89efb94fec9c78caab7ec4079bfe9e3f4e56a9a4 (patch)
tree7dd8b635def05ffa9b8bc15d4805c792b00dad22 /prism/util/pm_integer.c
parent42930d28a48bf7495180e81fd6e5cf742f3f47c7 (diff)
[ruby/prism] Reconfigure rationals
This eliminates the subnode on RationalNode and replaces it with two integer fields, which represent the ratio for the rational. It also reduces those two integers if they both fit into 32 bits. Importantly, this PR does not implement bignum reduction. That's something I'd like to consider for the future, but it's simple enough for now to leave them unreduced, which makes it more useful than it used to be. https://github.com/ruby/prism/commit/86e06c7068
Diffstat (limited to 'prism/util/pm_integer.c')
-rw-r--r--prism/util/pm_integer.c38
1 files changed, 37 insertions, 1 deletions
diff --git a/prism/util/pm_integer.c b/prism/util/pm_integer.c
index e523bae90b..015789ccec 100644
--- a/prism/util/pm_integer.c
+++ b/prism/util/pm_integer.c
@@ -473,13 +473,16 @@ pm_integer_parse_big(pm_integer_t *integer, uint32_t multiplier, const uint8_t *
*/
PRISM_EXPORTED_FUNCTION 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;
@@ -573,6 +576,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