diff --git a/src/bignum.h b/src/bignum.h index 4d6b5619e88bdc18d6d4bf7d9e7586d302f18927..f72c10c2d4afd39f577350ea8512fe31c853b72c 100644 --- a/src/bignum.h +++ b/src/bignum.h @@ -9,7 +9,14 @@ #define INT_TYPE_SIGN(x) ((x) < 0) +#if HAVE_NICE_FPU_DIVISION #define INT_TYPE_MUL_OVERFLOW(a, b) ((b) && ((a)*(b))/(b) != (a)) +#else +#define INT_TYPE_MUL_OVERFLOW(a, b) \ + ((b) && (INT_TYPE_DIV_OVERFLOW(a, b) || ((a)*(b))/(b) != (a))) +#endif + +#define INT_TYPE_DIV_OVERFLOW(a, b) (INT_TYPE_NEG_OVERFLOW(a) && (b) == -1) #define INT_TYPE_NEG_OVERFLOW(x) ((x) == -(x)) @@ -52,6 +59,8 @@ int int64_from_bignum(INT64 *i, struct object *bignum); #else +#define INT_TYPE_DIV_OVERFLOW(a, b) ((a) == -(a) && (b) == -1) + #define push_int64(i) push_int((INT_TYPE)i) #define INT_TYPE_MUL_OVERFLOW(a, b) 0 diff --git a/src/operators.c b/src/operators.c index f135e0f040689858e4f25d57be7f03b6080fa5a2..5bc9ea23764a05f631aef8560e464822e1ee6e8e 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.65 1999/10/29 08:21:50 hubbe Exp $"); +RCSID("$Id: operators.c,v 1.66 1999/10/30 13:18:49 noring Exp $"); #include "interpret.h" #include "svalue.h" #include "multiset.h" @@ -1538,6 +1538,7 @@ void o_divide(void) switch(sp[-2].type) { case T_OBJECT: + do_lfun_division: CALL_OPERATOR(LFUN_DIVIDE,2); break; @@ -1571,16 +1572,31 @@ void o_divide(void) case T_INT: { INT32 tmp; + if (sp[-1].u.integer == 0) OP_DIVISION_BY_ZERO_ERROR("`/"); - sp--; - tmp=sp[-1].u.integer/sp[0].u.integer; + if(INT_TYPE_DIV_OVERFLOW(sp[-2].u.integer, sp[-1].u.integer)) + { +#ifdef AUTO_BIGNUM + stack_swap(); + convert_stack_top_to_bignum(); + stack_swap(); + goto do_lfun_division; +#else + /* It's not possible to do MININT/-1 (it gives FPU exception on + some CPU:s), thus we return what MININT*-1 returns: MININT. */ + tmp = sp[-2].u.integer; +#endif /* AUTO_BIGNUM */ + } + else + tmp = sp[-2].u.integer/sp[-1].u.integer; + sp--; + /* What is this trying to solve? /Noring */ if((sp[-1].u.integer<0) != (sp[0].u.integer<0)) if(tmp*sp[0].u.integer!=sp[-1].u.integer) tmp--; - sp[-1].u.integer=tmp; return; } diff --git a/src/testsuite.in b/src/testsuite.in index fe99b2f318c7c620f0ce5954f5ee256e8f298bec..8135792e0b1609afa1392fc3b5f560011b12d15b 100644 --- a/src/testsuite.in +++ b/src/testsuite.in @@ -1,4 +1,4 @@ -test_true([["$Id: testsuite.in,v 1.213 1999/10/29 03:37:42 mast Exp $"]]) +test_true([["$Id: testsuite.in,v 1.214 1999/10/30 13:18:50 noring Exp $"]]) cond([[all_constants()->_verify_internals]], [[ @@ -20,6 +20,7 @@ test_eq(0x80000000-0x80000000, 0) test_eq(0xf0000000-0xf0000000, 0) test_eq(0x80000001-0x80000000, 1) test_eq(0x80000000-0x80000001,-1) +test_eq(-2147483648*-1, -2147483648/-1) test_true([[1.0e-40]]) test_eq([[#"foo bar"]],[["foo\nbar"]]) @@ -1514,6 +1515,9 @@ cond([[ sizeof( cpp("__AUTO_BIGNUM__")/"__AUTO_BIGNUM__" ) == 1 ]], cond([[ sizeof( cpp("__AUTO_BIGNUM__")/"__AUTO_BIGNUM__" ) == 1 ]], [[ + test_eq(2147483648, -2147483648/-1) + test_eq(2147483648, -2147483648*-1) + test_true([[ random(0x7fffffff)+1 ]]) test_true([[ random(0x7ffffffff)+1 ]]) test_true([[ sqrt(0x7fffffff)+1 ]])