diff --git a/src/bignum.c b/src/bignum.c index 2f6ad8caf2816df5718396dcf1085e8b3bc31b02..f60992c1f9558f83307f35e340eca171a2e60a72 100644 --- a/src/bignum.c +++ b/src/bignum.c @@ -55,6 +55,17 @@ struct object *bignum_from_svalue(struct svalue *s) return (--sp)->u.object; } +struct pike_string *string_from_bignum(struct object *o, int base) +{ + push_int(base); + safe_apply(o, "digits", 1); + + if(sp[-1].type != T_STRING) + error("Gmp.mpz string conversion failed.\n"); + + return (--sp)->u.string; +} + void convert_svalue_to_bignum(struct svalue *s) { push_svalue(s); diff --git a/src/bignum.h b/src/bignum.h index 83ea61aaa6667a75ec97bdd77c42978c7ca4c3fa..544d10494e6bd1bb8ede394b83172c80d1a494d1 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -5,10 +5,9 @@ #ifdef AUTO_BIGNUM +/* Note: These functions assume some properties of the CPU. */ -/* NOTE: These functions assume some properties of the CPU. */ - -#define INT_TYPE_SIGN(x) ((x) < 0 ? -1 : 1) +#define INT_TYPE_SIGN(x) ((x) < 0) #define INT_TYPE_MUL_OVERFLOW(a, b) ((b) && ((a)*(b))/(b) != (a)) @@ -18,16 +17,23 @@ (INT_TYPE_SIGN(a) == INT_TYPE_SIGN(b) && \ INT_TYPE_SIGN(a) != INT_TYPE_SIGN((a)+(b))) -#define INT_TYPE_SUB_OVERFFLOW(a, b) INT_TYPE_ADD_OVERFLOW((a), -(b)) +#define INT_TYPE_SUB_OVERFLOW(a, b) \ + (INT_TYPE_SIGN(a) != INT_TYPE_SIGN(b) && \ + INT_TYPE_SIGN(a) != INT_TYPE_SIGN((a)-(b))) -#define INT_TYPE_SUB_OVERFLOW(a, b) INT_TYPE_ADD_OVERFLOW((a), -(b)) -#define INT_TYPE_ASL_OVERFLOW(a, b) ((((a)<<(b))>>(b)) != (a)) +#define INT_TYPE_LSH_OVERFLOW(a, b) \ + (((INT_TYPE)sizeof(INT_TYPE))*CHAR_BIT <= (b) || \ + (((a)<<(b))>>(b)) != (a)) +/* Note: If this gives overflow, set the result to zero. */ +#define INT_TYPE_RSH_OVERFLOW(a, b) \ + (((INT_TYPE)sizeof(INT_TYPE))*CHAR_BIT <= (b)) /* Prototypes begin here */ void convert_stack_top_to_bignum(void); struct object *make_bignum_object(void); struct object *bignum_from_svalue(struct svalue *s); +struct pike_string *string_from_bignum(struct object *o, int base); void convert_svalue_to_bignum(struct svalue *s); /* Prototypes end here */ diff --git a/src/operators.c b/src/operators.c index 0c02531d5f4c50eb9184d4004ae2c8c466c5e713..a8f5afd07176d2c2098c5db52dd1a25182413e20 100644 --- a/src/operators.c +++ b/src/operators.c @@ -6,7 +6,7 @@ /**/ #include "global.h" #include <math.h> -RCSID("$Id: operators.c,v 1.62 1999/10/09 23:29:01 hubbe Exp $"); +RCSID("$Id: operators.c,v 1.63 1999/10/15 21:08:44 noring Exp $"); #include "interpret.h" #include "svalue.h" #include "multiset.h" @@ -675,6 +675,14 @@ void o_subtract(void) return; case T_INT: +#ifdef AUTO_BIGNUM + if(INT_TYPE_SUB_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) + { + convert_stack_top_to_bignum(); + f_minus(2); + return; + } +#endif /* AUTO_BIGNUM */ sp--; sp[-1].u.integer -= sp[0].u.integer; return; @@ -1116,6 +1124,11 @@ static int generate_xor(node *n) void o_lsh(void) { +#ifdef AUTO_BIGNUM + if(INT_TYPE_LSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) + convert_stack_top_to_bignum(); +#endif /* AUTO_BIGNUM */ + if(sp[-1].type != T_INT || sp[-2].type != T_INT) { int args = 2; @@ -1161,6 +1174,16 @@ void o_rsh(void) SIMPLE_BAD_ARG_ERROR("`>>", 1, "int|object"); SIMPLE_BAD_ARG_ERROR("`>>", 2, "int|object"); } + +#ifdef AUTO_BIGNUM + if(INT_TYPE_RSH_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) + { + sp--; + sp[-1].u.integer = 0; + return; + } +#endif /* AUTO_BIGNUM */ + sp--; sp[-1].u.integer = sp[-1].u.integer >> sp->u.integer; } @@ -1832,6 +1855,7 @@ void o_negate(void) switch(sp[-1].type) { case T_OBJECT: + do_lfun_negate: CALL_OPERATOR(LFUN_SUBTRACT,1); break; @@ -1840,6 +1864,13 @@ void o_negate(void) return; case T_INT: +#ifdef AUTO_BIGNUM + if(INT_TYPE_NEG_OVERFLOW(sp[-1].u.integer)) + { + convert_stack_top_to_bignum(); + goto do_lfun_negate; + } +#endif /* AUTO_BIGNUM */ sp[-1].u.integer = - sp[-1].u.integer; return;