From 4f705d90aaeb76b1f1d813c5c2963c637c4b0fa6 Mon Sep 17 00:00:00 2001 From: Bill Hails Date: Tue, 9 Apr 2024 08:01:34 +0100 Subject: [PATCH] MaybeBigInts can now carry irrationals --- src/arithmetic.c | 254 +++++++++++++++++++++++++---------------------- src/bigint.c | 122 +++++++++++++++-------- src/bigint.h | 15 ++- src/bytecode.c | 34 ++++--- src/common.h | 1 + utils.sh | 2 +- 6 files changed, 257 insertions(+), 171 deletions(-) diff --git a/src/arithmetic.c b/src/arithmetic.c index 9785313..be587af 100644 --- a/src/arithmetic.c +++ b/src/arithmetic.c @@ -37,7 +37,7 @@ typedef Value (*IntegerBinOp)(Value, Value); typedef Value (*ParameterizedBinOp)(IntegerBinOp, Value, Value); -int rational_flag = 0; +bool arithmetic_initialized = false; static Value One = { .type = VALUE_TYPE_STDINT, @@ -105,8 +105,8 @@ static inline Cmp int_cmp_ii(Value left, Value right) { CMP_GT; } -static Cmp int_cmp(Value left, Value right) { - ENTER(int_cmp); +static Cmp intCmp(Value left, Value right) { + ENTER(intCmp); Cmp res; if (IS_BIGINT(left)) { if (IS_BIGINT(right)) { @@ -121,7 +121,7 @@ static Cmp int_cmp(Value left, Value right) { res = int_cmp_ii(left, right); } } - LEAVE(int_cmp); + LEAVE(intCmp); return res; } @@ -138,8 +138,8 @@ static Value safe_add(int a, int b) { } } -static Value int_add(Value left, Value right) { - ENTER(int_add); +static Value intAdd(Value left, Value right) { + ENTER(intAdd); Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -161,7 +161,7 @@ static Value int_add(Value left, Value right) { res = safe_add(left.val.stdint, right.val.stdint); } } - LEAVE(int_add); + LEAVE(intAdd); UNPROTECT(save); return res; } @@ -179,7 +179,7 @@ static Value safe_mul(int a, int b) { } } -static Value int_mul(Value left, Value right) { +static Value intMul(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -218,7 +218,7 @@ static Value safe_sub(int a, int b) { } } -static Value int_sub(Value left, Value right) { +static Value intSub(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -244,7 +244,7 @@ static Value int_sub(Value left, Value right) { return res; } -static Value int_div(Value left, Value right) { +static Value intDiv(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -296,7 +296,7 @@ static Value safe_pow(int a, int b) { } } -static Value int_pow(Value left, Value right) { +static Value intPow(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -322,7 +322,7 @@ static Value int_pow(Value left, Value right) { return res; } -static Value int_mod(Value left, Value right) { +static Value intMod(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -374,7 +374,7 @@ static int gcd (int a, int b) { return gcd; } -static Value int_gcd(Value left, Value right) { +static Value intGcd(Value left, Value right) { Value res; int save = PROTECT(NULL); if (IS_BIGINT(left)) { @@ -400,7 +400,7 @@ static Value int_gcd(Value left, Value right) { return res; } -static void int_neg_in_place(Value *v) { +static void intNegInPlace(Value *v) { if (IS_BIGINT(*v)) { negateBigInt(v->val.bigint); } else { @@ -408,7 +408,7 @@ static void int_neg_in_place(Value *v) { } } -static Value int_neg(Value v) { +static Value intNeg(Value v) { int save = PROTECT(NULL); if (IS_BIGINT(v)) { BigInt *bi = copyBigInt(v.val.bigint); @@ -422,7 +422,7 @@ static Value int_neg(Value v) { return v; } -static bool int_isneg(Value v) { +static bool intIsNeg(Value v) { if (IS_BIGINT(v)) { return isNegBigInt(v.val.bigint); } else { @@ -440,18 +440,18 @@ static bool int_isneg(Value v) { # define ASSERT_RATIONAL(x) #endif -static Cmp _rat_cmp(Value left, Value right) { - ENTER(_rat_cmp); +static Cmp ratCmp(Value left, Value right) { + ENTER(ratCmp); ASSERT_RATIONAL(left); ASSERT_RATIONAL(right); - Value ad = int_mul(left.val.vec->values[NUMERATOR], + Value ad = intMul(left.val.vec->values[NUMERATOR], right.val.vec->values[DENOMINATOR]); int save = protectValue(ad); - Value bc = int_mul(left.val.vec->values[DENOMINATOR], + Value bc = intMul(left.val.vec->values[DENOMINATOR], right.val.vec->values[NUMERATOR]); protectValue(bc); - Cmp res = int_cmp(ad, bc); - LEAVE(_rat_cmp); + Cmp res = intCmp(ad, bc); + LEAVE(ratCmp); UNPROTECT(save); return res; } @@ -467,32 +467,6 @@ static Value makeRational(Value numerator, Value denominator) { return res; } -Cmp ncmp(Value left, Value right) { - ENTER(ncmp); - Cmp res; - int save = PROTECT(NULL); - if (left.type == VALUE_TYPE_RATIONAL) { - if (right.type == VALUE_TYPE_RATIONAL) { - res = _rat_cmp(left, right); - } else { - right = makeRational(right, One); - protectValue(right); - res = _rat_cmp(left, right); - } - } else { - if (right.type == VALUE_TYPE_RATIONAL) { - left = makeRational(left, One); - protectValue(left); - res = _rat_cmp(left, right); - } else { - res = int_cmp(left, right); - } - } - LEAVE(ncmp); - UNPROTECT(save); - return res; -} - static Value ratOp(Value left, Value right, ParameterizedBinOp op, IntegerBinOp intOp, bool simplify) { ENTER(ratOp); IFDEBUG(ppNumber(left)); @@ -542,20 +516,20 @@ static Value ratSimplify(Value numerator, Value denominator) { ENTER(ratSimplify); IFDEBUG(ppNumber(numerator)); IFDEBUG(ppNumber(denominator)); - Value gcd = int_gcd(numerator, denominator); + Value gcd = intGcd(numerator, denominator); int save = protectValue(gcd); Value res; - if (int_cmp(gcd, One) != CMP_EQ) { - numerator = int_div(numerator, gcd); + if (intCmp(gcd, One) != CMP_EQ) { + numerator = intDiv(numerator, gcd); protectValue(numerator); - denominator = int_div(denominator, gcd); + denominator = intDiv(denominator, gcd); protectValue(denominator); } - if (int_isneg(denominator)) { - int_neg_in_place(&numerator); - int_neg_in_place(&denominator); + if (intIsNeg(denominator)) { + intNegInPlace(&numerator); + intNegInPlace(&denominator); } - if (int_cmp(denominator, One) == CMP_EQ) { + if (intCmp(denominator, One) == CMP_EQ) { res = numerator; } else { res = makeRational(numerator, denominator); @@ -567,22 +541,23 @@ static Value ratSimplify(Value numerator, Value denominator) { return res; } -static Value _rat_add_sub(IntegerBinOp base_op, Value left, Value right) { +// a/b o c/d = (ad o bc) / bd +static Value rat_ad_bc_cd(IntegerBinOp base_op, Value left, Value right) { ENTER(rat_add_sub); ASSERT_RATIONAL(left); ASSERT_RATIONAL(right); Value a1b2 = - int_mul(left.val.vec->values[NUMERATOR], + intMul(left.val.vec->values[NUMERATOR], right.val.vec->values[DENOMINATOR]); int save = protectValue(a1b2); Value a2b1 = - int_mul(left.val.vec->values[DENOMINATOR], + intMul(left.val.vec->values[DENOMINATOR], right.val.vec->values[NUMERATOR]); protectValue(a2b1); Value numerator = base_op(a1b2, a2b1); protectValue(numerator); Value denominator = - int_mul(left.val.vec->values[DENOMINATOR], + intMul(left.val.vec->values[DENOMINATOR], right.val.vec->values[DENOMINATOR]); protectValue(denominator); Value res = ratSimplify(numerator, denominator); @@ -591,24 +566,9 @@ static Value _rat_add_sub(IntegerBinOp base_op, Value left, Value right) { return res; } -Value nadd(Value left, Value right) { - ENTER(nadd); - IFDEBUG(ppNumber(left)); - IFDEBUG(ppNumber(right)); - Value res = ratOp(left, right, _rat_add_sub, int_add, true); - LEAVE(nadd); - return res; -} - -Value nsub(Value left, Value right) { - ENTER(nsub); - Value res = ratOp(left, right, _rat_add_sub, int_sub, true); - LEAVE(nsub); - return res; -} - -static Value _rat_mul(IntegerBinOp base_op, Value left, Value right) { - ENTER(_rat_mul); +// a/b o c/d = ac o bd +static Value rat_ac_bd(IntegerBinOp base_op, Value left, Value right) { + ENTER(rat_ac_bd); ASSERT_RATIONAL(left); ASSERT_RATIONAL(right); IFDEBUG(ppNumber(left)); @@ -623,35 +583,82 @@ static Value _rat_mul(IntegerBinOp base_op, Value left, Value right) { protectValue(denominator); Value res = ratSimplify(numerator, denominator); protectValue(res); - LEAVE(_rat_mul); + LEAVE(rat_ac_bd); IFDEBUG(ppNumber(res)); UNPROTECT(save); return res; } -Value nmul(Value left, Value right) { - ENTER(nmul); +static Value ratDiv(IntegerBinOp base_op, Value left, Value right) { + ENTER(ratDiv); + ASSERT_RATIONAL(left); + ASSERT_RATIONAL(right); IFDEBUG(ppNumber(left)); IFDEBUG(ppNumber(right)); - Value res = ratOp(left, right, _rat_mul, int_mul, true); - int save = protectValue(res); - LEAVE(nmul); + Value newRight = makeRational(right.val.vec->values[DENOMINATOR], right.val.vec->values[NUMERATOR]); + int save = protectValue(newRight); + Value res = rat_ac_bd(base_op, left, newRight); + protectValue(res); + LEAVE(ratDiv); IFDEBUG(ppNumber(res)); UNPROTECT(save); return res; } -static Value _rat_div(IntegerBinOp base_op, Value left, Value right) { - ENTER(_rat_div); +static Value ratPow(Value left, Value right) { + ENTER(ratPow); ASSERT_RATIONAL(left); - ASSERT_RATIONAL(right); + Value numerator = left.val.vec->values[NUMERATOR]; + Value denominator = left.val.vec->values[DENOMINATOR]; + numerator = intPow(numerator, right); + int save = protectValue(numerator); + denominator = intPow(denominator, right); + protectValue(denominator); + Value res = ratSimplify(numerator, denominator); + protectValue(res); + LEAVE(ratPow); + IFDEBUG(ppNumber(res)); + UNPROTECT(save); + return res; +} + +#ifdef SAFETY_CHECKS +# define CHECK_INITIALIZED() do { \ + if (!arithmetic_initialized) { \ + cant_happen("arithmetic not initialized yet"); \ + } \ +} while(0) +#else +# define CHECK_INITIALIZED() +#endif + + +Value nadd(Value left, Value right) { + ENTER(nadd); + CHECK_INITIALIZED(); IFDEBUG(ppNumber(left)); IFDEBUG(ppNumber(right)); - Value newRight = makeRational(right.val.vec->values[DENOMINATOR], right.val.vec->values[NUMERATOR]); - int save = protectValue(newRight); - Value res = _rat_mul(base_op, left, newRight); - protectValue(res); - LEAVE(_rat_div); + Value res = ratOp(left, right, rat_ad_bc_cd, intAdd, true); + LEAVE(nadd); + return res; +} + +Value nsub(Value left, Value right) { + ENTER(nsub); + CHECK_INITIALIZED(); + Value res = ratOp(left, right, rat_ad_bc_cd, intSub, true); + LEAVE(nsub); + return res; +} + +Value nmul(Value left, Value right) { + ENTER(nmul); + CHECK_INITIALIZED(); + IFDEBUG(ppNumber(left)); + IFDEBUG(ppNumber(right)); + Value res = ratOp(left, right, rat_ac_bd, intMul, true); + int save = protectValue(res); + LEAVE(nmul); IFDEBUG(ppNumber(res)); UNPROTECT(save); return res; @@ -659,8 +666,9 @@ static Value _rat_div(IntegerBinOp base_op, Value left, Value right) { Value ndiv(Value left, Value right) { ENTER(ndiv); - // N.B. int_mul not int_div - Value res = ratOp(left, right, _rat_div, int_mul, false); + CHECK_INITIALIZED(); + // N.B. intMul not intDiv + Value res = ratOp(left, right, ratDiv, intMul, false); int save = protectValue(res); LEAVE(ndiv); IFDEBUG(ppNumber(res)); @@ -670,30 +678,15 @@ Value ndiv(Value left, Value right) { Value nmod(Value left, Value right) { ENTER(nmod); - Value res = ratOp(left, right, _rat_add_sub, int_mod, true); + CHECK_INITIALIZED(); + Value res = ratOp(left, right, rat_ad_bc_cd, intMod, true); LEAVE(nmod); 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_pow(numerator, right); - int save = protectValue(numerator); - denominator = int_pow(denominator, right); - protectValue(denominator); - Value res = ratSimplify(numerator, denominator); - protectValue(res); - LEAVE(_ratPower); - IFDEBUG(ppNumber(res)); - UNPROTECT(save); - return res; -} - Value npow(Value left, Value right) { ENTER(npow); + CHECK_INITIALIZED(); IFDEBUG(ppNumber(left)); IFDEBUG(ppNumber(right)); Value res; @@ -704,14 +697,14 @@ Value npow(Value left, Value right) { cant_happen("raising numbers to a rational power not supported yet"); } else { // only left rational - res = _ratPower(left, right); + res = ratPow(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_pow(left, right); + res = intPow(left, right); protectValue(res); } LEAVE(npow); @@ -720,16 +713,44 @@ Value npow(Value left, Value right) { return res; } +Cmp ncmp(Value left, Value right) { + ENTER(ncmp); + CHECK_INITIALIZED(); + Cmp res; + int save = PROTECT(NULL); + if (left.type == VALUE_TYPE_RATIONAL) { + if (right.type == VALUE_TYPE_RATIONAL) { + res = ratCmp(left, right); + } else { + right = makeRational(right, One); + protectValue(right); + res = ratCmp(left, right); + } + } else { + if (right.type == VALUE_TYPE_RATIONAL) { + left = makeRational(left, One); + protectValue(left); + res = ratCmp(left, right); + } else { + res = intCmp(left, right); + } + } + LEAVE(ncmp); + UNPROTECT(save); + return res; +} + Value nneg(Value v) { ENTER(nneg); + CHECK_INITIALIZED(); Value res; if (v.type == VALUE_TYPE_RATIONAL) { - Value numerator = int_neg(v.val.vec->values[NUMERATOR]); + Value numerator = intNeg(v.val.vec->values[NUMERATOR]); int save = protectValue(numerator); res = makeRational(numerator, v.val.vec->values[DENOMINATOR]); UNPROTECT(save); } else { - res = int_neg(v); + res = intNeg(v); } LEAVE(nneg); return res; @@ -742,6 +763,7 @@ void init_arithmetic() { BigInt *one = bigIntFromInt(1); One.type = VALUE_TYPE_BIGINT; One.val = VALUE_VAL_BIGINT(one); + arithmetic_initialized = true; } void markArithmetic() { diff --git a/src/bigint.c b/src/bigint.c index 1c172de..59007cd 100644 --- a/src/bigint.c +++ b/src/bigint.c @@ -1270,27 +1270,31 @@ double bigint_double(const bigint * src) { // additional CEKF code MaybeBigInt *newMaybeBigInt(bigint bi) { + ENTER(newMaybeBigInt); MaybeBigInt *x = NEW(MaybeBigInt, OBJTYPE_MAYBEBIGINT); DEBUG("newMaybeBigInt %p", x); - x->little = 0; - x->fake = false; - x->bi = bi; + x->type = BI_BIG; + x->big = bi; + LEAVE(newMaybeBigInt); return x; } BigInt *newBigInt(bigint bi) { + ENTER(newBigInt); BigInt *x = NEW(BigInt, OBJTYPE_BIGINT); DEBUG("newBigInt %p", x); x->bi = bi; + LEAVE(newBigInt); return x; } MaybeBigInt *fakeBigInt(int little) { - MaybeBigInt *x = NEW(MaybeBigInt, OBJTYPE_BIGINT); + ENTER(fakeBigInt); + MaybeBigInt *x = NEW(MaybeBigInt, OBJTYPE_MAYBEBIGINT); DEBUG("fakeBigInt %p", x); - x->little = little; - x->fake = true; - bzero(&x->bi, sizeof(bigint)); + x->small = little; + x->type = BI_SMALL; + LEAVE(fakeBigInt); return x; } @@ -1355,15 +1359,19 @@ void markMaybeBigInt(MaybeBigInt *x) { } void freeBigInt(BigInt *x) { + ENTER(freeBigInt); FREE_ARRAY(bigint_word, x->bi.words, x->bi.capacity); FREE(x, BigInt); + LEAVE(freeBigInt); } void freeMaybeBigInt(MaybeBigInt *x) { - if (!x->fake) { - FREE_ARRAY(bigint_word, x->bi.words, x->bi.capacity); + ENTER(freeMaybeBigInt); + if (x->type == BI_BIG) { + FREE_ARRAY(bigint_word, x->big.words, x->big.capacity); } FREE(x, MaybeBigInt); + LEAVE(freeMaybeBigInt); } void printMaybeBigInt(MaybeBigInt *x, int depth) { @@ -1398,10 +1406,18 @@ void fprintMaybeBigInt(FILE *f, MaybeBigInt *x) { fprintf(f, ""); return; } - if (x->fake) { - fprintf(f, "%d", x->little); - } else { - bigint_fprint(f, &x->bi); + switch (x->type) { + case BI_SMALL: + fprintf(f, "%d", x->small); + break; + case BI_BIG: + bigint_fprint(f, &x->big); + break; + case BI_IRRATIONAL: + fprintf(f, "%f", x->irrational); + break; + default: + cant_happen("unrecognized type of MaybeBigInt: %d", x->type); } } @@ -1419,32 +1435,60 @@ Cmp cmpBigIntInt(BigInt *a, int b) { } Cmp cmpMaybeBigInt(MaybeBigInt *x, MaybeBigInt *y) { - if (x->fake) { - if (y->fake) { - return x->little < y->little ? - -1 : - x->little == y->little ? - 0 : - 1; - } else { - bigint bx; - bigint_init(&bx); - bigint_from_int(&bx, x->little); - Cmp res = (Cmp) bigint_cmp(&bx, &y->bi); - bigint_free(&bx); - return res; - } - } else { - if (y->fake) { - bigint by; - bigint_init(&by); - bigint_from_int(&by, y->little); - Cmp res = (Cmp) bigint_cmp(&x->bi, &by); - bigint_free(&by); - return res; - } else { - return (Cmp) bigint_cmp(&x->bi, &y->bi); - } + switch (x->type) { + case BI_SMALL: + switch (y->type) { + case BI_SMALL: + return x->small < y->small ? -1 : + x->small == y->small ? 0 : 1; + case BI_BIG: + bigint bx; + bigint_init(&bx); + bigint_from_int(&bx, x->small); + Cmp res = (Cmp) bigint_cmp(&bx, &y->big); + bigint_free(&bx); + return res; + case BI_IRRATIONAL: + return x->small < y->irrational ? -1 : + x->small == y->irrational ? 0 : 1; + default: + cant_happen("unrecognized type of MaybeBigInt: %d", x->type); + } + break; + case BI_BIG: + switch (y->type) { + case BI_SMALL: + bigint by; + bigint_init(&by); + bigint_from_int(&by, y->small); + Cmp res = (Cmp) bigint_cmp(&x->big, &by); + bigint_free(&by); + return res; + case BI_BIG: + return (Cmp) bigint_cmp(&x->big, &y->big); + case BI_IRRATIONAL: + cant_happen("attempt to compare bigint and rational"); + break; + default: + cant_happen("unrecognized type of MaybeBigInt: %d", x->type); + } + break; + case BI_IRRATIONAL: + switch (y->type) { + case BI_SMALL: + return x->irrational < y->small ? -1 : + x->irrational == y->small ? 0 : 1; + case BI_BIG: + cant_happen("attempt to compare bigint and rational"); + case BI_IRRATIONAL: + return x->irrational < y->irrational ? -1 : + x->irrational == y->irrational ? 0 : 1; + default: + cant_happen("unrecognized type of MaybeBigInt: %d", x->type); + } + break; + default: + cant_happen("unrecognized type of MaybeBigInt: %d", x->type); } } diff --git a/src/bigint.h b/src/bigint.h index 0d35b5a..9fad105 100644 --- a/src/bigint.h +++ b/src/bigint.h @@ -42,11 +42,20 @@ extern "C" { // CEKF wrapper for memory management // compile-time bigint + typedef enum MaybeBigIntType { + BI_BIG, + BI_SMALL, + BI_IRRATIONAL + } MaybeBigIntType; + typedef struct MaybeBigInt { Header header; - bigint bi; - bool fake; - int little; + MaybeBigIntType type; + union { + bigint big; + int small; + double irrational; + }; } MaybeBigInt; // run-time bigint diff --git a/src/bytecode.c b/src/bytecode.c index f7f4fe3..d48abdb 100644 --- a/src/bytecode.c +++ b/src/bytecode.c @@ -379,12 +379,17 @@ void writeCexpIntCond(CexpIntCondCases *x, ByteCodeArray *b) { for (CexpIntCondCases *xx = x; xx != NULL; xx = xx->next) { if (xx->next == NULL) break; // default case doesn't get a test - if (xx->option->fake) { - addByte(b, BYTECODE_STDINT); - addInt(b, xx->option->little); - } else { - addByte(b, BYTECODE_BIGINT); - addBig(b, xx->option->bi); + switch (xx->option->type) { + case BI_SMALL: + addByte(b, BYTECODE_STDINT); + addInt(b, xx->option->small); + break; + case BI_BIG: + addByte(b, BYTECODE_BIGINT); + addBig(b, xx->option->big); + break; + default: + cant_happen("unsupported MaybeBigIntType %d", xx->option->type); } dispatches[i++] = reserveWord(b); } @@ -560,12 +565,17 @@ void writeAexp(Aexp *x, ByteCodeArray *b) { } break; case AEXP_TYPE_BIGINTEGER:{ - if (x->val.biginteger->fake) { - addByte(b, BYTECODE_STDINT); - addInt(b, x->val.biginteger->little); - } else { - addByte(b, BYTECODE_BIGINT); - addBig(b, x->val.biginteger->bi); + switch (x->val.biginteger->type) { + case BI_SMALL: + addByte(b, BYTECODE_STDINT); + addInt(b, x->val.biginteger->small); + break; + case BI_BIG: + addByte(b, BYTECODE_BIGINT); + addBig(b, x->val.biginteger->big); + break; + default: + cant_happen("unsupported MaybeBigInt type %d", x->val.biginteger->type); } } break; diff --git a/src/common.h b/src/common.h index f81a1a2..98b274d 100644 --- a/src/common.h +++ b/src/common.h @@ -25,6 +25,7 @@ # define DEBUG_ANY # ifdef DEBUG_ANY +// # define DEBUG_BIGINT // # define DEBUG_STACK // # define DEBUG_STEP // if DEBUG_STEP is defined, this sleeps for 1 second between each machine step diff --git a/utils.sh b/utils.sh index 9e74edd..aa76fa6 100644 --- a/utils.sh +++ b/utils.sh @@ -1,3 +1,3 @@ fnd () { - grep -rwn $1 src generated + grep -Irwn $1 src generated }