From e4a15cba339ac007f5dd454341e9bba3ce87d054 Mon Sep 17 00:00:00 2001 From: Vitor Santos Costa Date: Mon, 30 Aug 2010 21:50:33 -0500 Subject: [PATCH] div/2 operators (from WG17 and #176) --- C/arith2.c | 66 +++++++++++++++++++++++++++++++++++++++++++++ C/gmp_support.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- H/eval.h | 3 +++ docs/yap.tex | 4 +++ 4 files changed, 143 insertions(+), 1 deletion(-) diff --git a/C/arith2.c b/C/arith2.c index 4224b7a7f..d167a9939 100755 --- a/C/arith2.c +++ b/C/arith2.c @@ -101,6 +101,69 @@ zero_divisor: return Yap_ArithError(EVALUATION_ERROR_ZERO_DIVISOR, t2, "X is mod 0"); } +static Term +p_div2(Term t1, Term t2) { + switch (ETypeOfTerm(t1)) { + case (CELL)long_int_e: + switch (ETypeOfTerm(t2)) { + case (CELL)long_int_e: + /* two integers */ + { + Int i1 = IntegerOfTerm(t1); + Int i2 = IntegerOfTerm(t2); + Int res; + + if (i2 == 0) goto zero_divisor; + if (i1 == Int_MIN && i2 == -1) { +#ifdef USE_GMP + return Yap_gmp_add_ints(Int_MAX, 1); +#else + return Yap_ArithError(EVALUATION_ERROR_INT_OVERFLOW, t1, + "// /2 with %d and %d", i1, i2); +#endif + } + res = (i1 - i1%i2) / i2; + RINT(res); + } + case (CELL)double_e: + return Yap_ArithError(TYPE_ERROR_INTEGER, t2, "div/2"); + case (CELL)big_int_e: +#ifdef USE_GMP + return Yap_gmp_div_int_big(IntegerOfTerm(t1), t2); +#endif + default: + RERROR(); + break; + } + case (CELL)double_e: + return Yap_ArithError(TYPE_ERROR_INTEGER, t2, "div/2"); + case (CELL)big_int_e: +#ifdef USE_GMP + switch (ETypeOfTerm(t2)) { + case long_int_e: + /* modulo between bignum and integer */ + { + Int i2 = IntegerOfTerm(t2); + + if (i2 == 0) goto zero_divisor; + return Yap_gmp_div2_big_int(t1, i2); + } + case (CELL)big_int_e: + /* two bignums */ + return Yap_gmp_div2_big_big(t1, t2); + case double_e: + return Yap_ArithError(TYPE_ERROR_INTEGER, t2, "mod/2"); + default: + RERROR(); + } +#endif + default: + RERROR(); + } +zero_divisor: + return Yap_ArithError(EVALUATION_ERROR_ZERO_DIVISOR, t2, "X is div 0"); +} + static Term p_rem(Term t1, Term t2) { switch (ETypeOfTerm(t1)) { @@ -912,6 +975,8 @@ eval2(Int fi, Term t1, Term t2) { return p_times(t1, t2); case op_div: return p_div(t1, t2); + case op_idiv: + return p_div2(t1, t2); case op_and: return p_and(t1, t2); case op_or: @@ -959,6 +1024,7 @@ static InitBinEntry InitBinTab[] = { {"mod", op_mod}, {"rem", op_rem}, {"//", op_div}, + {"div", op_idiv}, {"<<", op_sll}, {">>", op_slr}, {"/\\", op_and}, diff --git a/C/gmp_support.c b/C/gmp_support.c index b47aba05f..d8f2afc0e 100755 --- a/C/gmp_support.c +++ b/C/gmp_support.c @@ -220,7 +220,7 @@ Yap_gmp_div_int_big(Int i, Term t) } } -/* div i / b using temporary bigint new */ +/* div b / i using temporary bigint new */ Term Yap_gmp_div_big_int(Term t, Int i) { @@ -263,6 +263,37 @@ Yap_gmp_div_big_int(Term t, Int i) } } +/* div b / i using temporary bigint new */ +Term +Yap_gmp_div2_big_int(Term t, Int i) +{ + CELL *pt = RepAppl(t); + if (pt[1] == BIG_INT) { + MP_INT new; + MP_INT *b = Yap_BigIntOfTerm(t); + + mpz_init_set(&new, b); + if (i > 0) { + mpz_fdiv_q_ui(&new, &new, i); + } else if (i == 0) { + return Yap_ArithError(EVALUATION_ERROR_ZERO_DIVISOR, MkIntTerm(0), "// /2"); + } else { + /* we do not handle MIN_INT */ + mpz_fdiv_q_ui(&new, &new, -i); + mpz_neg(&new, &new); + } + return MkBigAndClose(&new); + } else { + MP_RAT new; + MP_RAT *b = Yap_BigRatOfTerm(t); + + mpq_init(&new); + mpq_set_si(&new, i, 1L); + mpq_div(&new, b, &new); + return MkRatAndClose(&new); + } +} + /* and i - b using temporary bigint new */ Term Yap_gmp_and_int_big(Int i, Term t) @@ -533,6 +564,44 @@ Yap_gmp_div_big_big(Term t1, Term t2) } } +/* div i div b using temporary bigint new */ +Term +Yap_gmp_div2_big_big(Term t1, Term t2) +{ + CELL *pt1 = RepAppl(t1); + CELL *pt2 = RepAppl(t2); + if (pt1[1] == BIG_INT && pt2[1] == BIG_INT) { + MP_INT new; + MP_INT *b1 = Yap_BigIntOfTerm(t1); + MP_INT *b2 = Yap_BigIntOfTerm(t2); + + mpz_init_set(&new, b1); + mpz_fdiv_q(&new, &new, b2); + return MkBigAndClose(&new); + } else { + MP_RAT new; + MP_RAT *b1, bb1; + MP_RAT *b2, bb2; + if (pt1[1] == BIG_INT) { + b1 = &bb1; + mpq_init(b1); + mpq_set_z(b1, Yap_BigIntOfTerm(t1)); + } else { + b1 = Yap_BigRatOfTerm(t1); + } + if (pt2[1] == BIG_INT) { + b2 = &bb2; + mpq_init(b2); + mpq_set_z(b2, Yap_BigIntOfTerm(t2)); + } else { + b2 = Yap_BigRatOfTerm(t2); + } + mpq_init(&new); + mpq_div(&new, b1, b2); + return MkRatAndClose(&new); + } +} + Term Yap_gmp_and_big_big(Term t1, Term t2) { diff --git a/H/eval.h b/H/eval.h index 138916485..f3dd8cd65 100644 --- a/H/eval.h +++ b/H/eval.h @@ -108,6 +108,7 @@ typedef enum { op_mod, op_rem, op_div, + op_idiv, op_sll, op_slr, op_and, @@ -236,6 +237,7 @@ Term STD_PROTO(Yap_gmp_sub_big_int,(Term, Int)); Term STD_PROTO(Yap_gmp_mul_int_big,(Int, Term)); Term STD_PROTO(Yap_gmp_div_int_big,(Int, Term)); Term STD_PROTO(Yap_gmp_div_big_int,(Term, Int)); +Term STD_PROTO(Yap_gmp_div2_big_int,(Term, Int)); Term STD_PROTO(Yap_gmp_fdiv_int_big,(Int, Term)); Term STD_PROTO(Yap_gmp_fdiv_big_int,(Term, Int)); Term STD_PROTO(Yap_gmp_and_int_big,(Int, Term)); @@ -246,6 +248,7 @@ Term STD_PROTO(Yap_gmp_add_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_sub_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_mul_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_div_big_big,(Term, Term)); +Term STD_PROTO(Yap_gmp_div2_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_fdiv_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_and_big_big,(Term, Term)); Term STD_PROTO(Yap_gmp_ior_big_big,(Term, Term)); diff --git a/docs/yap.tex b/docs/yap.tex index e17376ddb..e638bb81a 100644 --- a/docs/yap.tex +++ b/docs/yap.tex @@ -3903,6 +3903,9 @@ Integer remainder. @item @var{X} rem @var{Y} [ISO] Integer remainder, the same as @code{mod}. +@item @var{X} div @var{Y} [ISO] +Integer division, as if defined by @code{(@var{X} - @var{X} mod @var{Y}) // @var{Y}}. + @item exp(@var{X}) [ISO] Natural exponential. @@ -15850,6 +15853,7 @@ a solution was found. Notice that you cannot create new slots if an YAP_EnterGoal goal is open. @item @code{YAP_Bool} YAP_RetryGoal(@code{YAP_dogoalinfo *} @var{infop}) + @findex YAP_RetryGoal (C-Interface function) Backtrack to a query created by @code{YAP_EnterGoal}. The query is given by the handle @var{infop}. Returns whether a new solution could