fixnum multiplication doesn't use long long

cvs
Slava Pestov 2004-09-03 22:37:25 +00:00
parent 541b6cd8d1
commit 5a0e002764
2 changed files with 53 additions and 4 deletions

View File

@ -30,6 +30,8 @@ typedef unsigned long int CELL;
#define CELLS ((signed)sizeof(CELL)) #define CELLS ((signed)sizeof(CELL))
#define WORD_SIZE (CELLS*8) #define WORD_SIZE (CELLS*8)
#define HALF_WORD_SIZE (CELLS*4)
#define HALF_WORD_MASK (((unsigned long)1<<HALF_WORD_SIZE)-1)
/* must always be 16 bits */ /* must always be 16 bits */
typedef unsigned short CHAR; typedef unsigned short CHAR;

View File

@ -48,13 +48,60 @@ CELL subtract_fixnum(FIXNUM x, FIXNUM y)
return tag_integer(x - y); return tag_integer(x - y);
} }
/**
* Multiply two integers, and trap overflow.
* I'm sure a more efficient algorithm exists.
*/
CELL multiply_fixnum(FIXNUM x, FIXNUM y) CELL multiply_fixnum(FIXNUM x, FIXNUM y)
{ {
long long result = (long long)x * (long long)y; bool negp;
if(result < FIXNUM_MIN || result > FIXNUM_MAX) FIXNUM hx, lx, hy, ly;
return tag_object(s48_long_long_to_bignum(result)); FIXNUM hprod, lprod, xprod, result;
if(x < 0)
{
negp = true;
x = -x;
}
else else
return tag_fixnum(result); negp = false;
if(y < 0)
{
negp = !negp;
y = -y;
}
hx = x >> HALF_WORD_SIZE;
hy = y >> HALF_WORD_SIZE;
hprod = hx * hy;
if(hprod != 0)
goto bignum;
lx = x & HALF_WORD_MASK;
ly = y & HALF_WORD_MASK;
lprod = lx * ly;
if(lprod > FIXNUM_MAX)
goto bignum;
xprod = lx * hy + hx * ly;
if(xprod > (FIXNUM_MAX >> HALF_WORD_SIZE))
goto bignum;
result = (xprod << HALF_WORD_SIZE) + lprod;
if(negp)
result = -result;
return tag_integer(result);
bignum: return tag_object(
s48_bignum_multiply(
s48_long_to_bignum(x),
s48_long_to_bignum(y)));
} }
CELL divint_fixnum(FIXNUM x, FIXNUM y) CELL divint_fixnum(FIXNUM x, FIXNUM y)