Skip to content

Commit

Permalink
allow rationals to be raised to integer powers, trap divide and mod b…
Browse files Browse the repository at this point in the history
…y zero
  • Loading branch information
billhails committed Apr 5, 2024
1 parent b5cbf20 commit c77f3ce
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 16 deletions.
4 changes: 3 additions & 1 deletion fn/rational.fn
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ print(#( "4 + 2 / 3 + 4", 4 + 2 / 3 + 4 ));
print(#( "4 + 2 / -3 + 4", 4 + 2 / -3 + 4 ));
print(#( "2 / 3 + 4 / 5", 2 / 3 + 4 / 5 ));
print(#( "(2 / 3) * (4 / 5)", (2 / 3) * (4 / 5) ));
print(#( "(2 / 3) / (4 / 5)", (2 / 3) / (4 / 5) ));
print(#( "(6 / 5)", (6 / 5) ));
print(#( "(2 / 3) / (6 / 5)", (2 / 3) / (6 / 5) ));
print(#( "(2 / 3) % (4 / 5)", (2 / 3) % (4 / 5) ));
print(#( "1914882942 ** 10", 1914882942 ** 10 ));
print(#( "1/3 % 8", 1/3 % 8 ));
print(#( "-9 % 8", -9 % 8 ));
print(#( "(1/2) ** 2", (1/2) ** 2 ));
print(#( "(1914882942 ** 5 / 5) % (2 / 3)", (1914882942 ** 5 / 5) % (2 / 3) ))

97 changes: 82 additions & 15 deletions src/arithmetic.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ static Value One = {
.val = VALUE_VAL_STDINT(1)
};

static Value Zero = {
.type = VALUE_TYPE_STDINT,
.val = VALUE_VAL_STDINT(0)
};

#ifdef DEBUG_ARITHMETIC
static void ppNumber(Value number) {
switch (number.type) {
Expand Down Expand Up @@ -98,6 +103,12 @@ static Value intValue(int i) {
# define ASSERT_STDINT(x)
#endif

static int littleCmp(Value left, Value right) {
ASSERT_STDINT(left);
ASSERT_STDINT(right);
return left.val.stdint < right.val.stdint ? -1 : left.val.stdint == right.val.stdint ? 0 : 1;
}

static Value littleAdd(Value left, Value right) {
ASSERT_STDINT(left);
ASSERT_STDINT(right);
Expand All @@ -119,6 +130,9 @@ static Value littleSub(Value left, Value right) {
static Value littleDivide(Value left, Value right) {
ASSERT_STDINT(left);
ASSERT_STDINT(right);
if (littleCmp(right, Zero) == 0) {
cant_happen("attempted div zero");
}
return intValue(left.val.stdint / right.val.stdint);
}

Expand All @@ -131,6 +145,9 @@ static Value littlePower(Value left, Value right) {
static Value littleModulo(Value left, Value right) {
ASSERT_STDINT(left);
ASSERT_STDINT(right);
if (littleCmp(right, Zero) == 0) {
cant_happen("attempted mod zero");
}
return intValue(left.val.stdint % right.val.stdint);
}

Expand All @@ -153,12 +170,6 @@ static Value littleGcd(Value left, Value right) {
return intValue(gcd(left.val.stdint, right.val.stdint));
}

static int littleCmp(Value left, Value right) {
ASSERT_STDINT(left);
ASSERT_STDINT(right);
return left.val.stdint < right.val.stdint ? -1 : left.val.stdint == right.val.stdint ? 0 : 1;
}

static void littleNeg(Value v) {
ASSERT_STDINT(v);
v.val.stdint = -v.val.stdint;
Expand All @@ -179,6 +190,14 @@ static bool littleIsNeg(Value v) {
# define ASSERT_BIGINT(x)
#endif

static int bigCmp(Value left, Value right) {
ENTER(bigCmp);
ASSERT_BIGINT(left);
ASSERT_BIGINT(right);
LEAVE(bigCmp);
return cmpBigInt(left.val.bigint, right.val.bigint);
}

static Value bigIntValue(BigInt *i) {
Value val;
val.type = VALUE_TYPE_BIGINT;
Expand Down Expand Up @@ -232,6 +251,9 @@ static Value bigDivide(Value left, Value right) {
IFDEBUG(ppNumber(right));
ASSERT_BIGINT(left);
ASSERT_BIGINT(right);
if (bigCmp(right, Zero) == 0) {
cant_happen("attempted div zero");
}
BigInt *result = divBigInt(left.val.bigint, right.val.bigint);
int save = PROTECT(result);
Value res = bigIntValue(result);
Expand All @@ -258,6 +280,9 @@ static Value bigModulo(Value left, Value right) {
ENTER(bigModulo);
ASSERT_BIGINT(left);
ASSERT_BIGINT(right);
if (bigCmp(right, Zero) == 0) {
cant_happen("attempted mod zero");
}
BigInt *result = modBigInt(left.val.bigint, right.val.bigint);
int save = PROTECT(result);
Value res = bigIntValue(result);
Expand All @@ -278,14 +303,6 @@ static Value bigGcd(Value left, Value right) {
return res;
}

static int bigCmp(Value left, Value right) {
ENTER(bigCmp);
ASSERT_BIGINT(left);
ASSERT_BIGINT(right);
LEAVE(bigCmp);
return cmpBigInt(left.val.bigint, right.val.bigint);
}

static void bigNeg(Value v) {
ASSERT_BIGINT(v);
negateBigInt(v.val.bigint);
Expand Down Expand Up @@ -499,6 +516,52 @@ static Value ratModulo(Value left, Value right) {
return res;
}

static Value _ratPower(Value left, Value right) {
ENTER(_ratPower);
ASSERT_RATIONAL(left);
Value numerator = left.val.vec->values[NUMERATOR];
Value denominator = left.val.vec->values[DENOMINATOR];
numerator = int_power(numerator, right);
int save = protectValue(numerator);
denominator = int_power(denominator, right);
protectValue(denominator);
Value res = ratSimplify(numerator, denominator);
protectValue(res);
LEAVE(_ratPower);
IFDEBUG(ppNumber(res));
UNPROTECT(save);
return res;
}

static Value ratPower(Value left, Value right) {
ENTER(ratPower);
LEAVE(ratPower);
IFDEBUG(ppNumber(left));
IFDEBUG(ppNumber(right));
Value res;
int save = protectValue(left);
protectValue(right);
if (left.type == VALUE_TYPE_RATIONAL) {
if (right.type == VALUE_TYPE_RATIONAL) {
cant_happen("raising numbers to a rational power not supported yet");
} else {
// only left rational
res = _ratPower(left, right);
protectValue(res);
}
} else if (right.type == VALUE_TYPE_RATIONAL) {
cant_happen("raising numbers to a rational power not supported yet");
} else {
// neither rational
res = int_power(left, right);
protectValue(res);
}
LEAVE(ratPower);
IFDEBUG(ppNumber(res));
UNPROTECT(save);
return res;
}

void init_arithmetic() {
if (bigint_flag) {
int_add = bigAdd;
Expand All @@ -511,6 +574,9 @@ void init_arithmetic() {
int_cmp = bigCmp;
int_neg = bigNeg;
int_isneg = bigIsNeg;
BigInt *zero = bigIntFromInt(0);
Zero.type = VALUE_TYPE_BIGINT;
Zero.val = VALUE_VAL_BIGINT(zero);
BigInt *one = bigIntFromInt(1);
One.type = VALUE_TYPE_BIGINT;
One.val = VALUE_VAL_BIGINT(one);
Expand All @@ -532,7 +598,7 @@ void init_arithmetic() {
sub = ratSub;
mul = ratMul;
divide = ratDivide;
power = int_power;
power = ratPower;
modulo = ratModulo;
} else {
add = int_add;
Expand All @@ -545,5 +611,6 @@ void init_arithmetic() {
}

void markArithmetic() {
markValue(Zero);
markValue(One);
}

0 comments on commit c77f3ce

Please sign in to comment.