fixnum multiplication doesn't use long long
parent
541b6cd8d1
commit
5a0e002764
|
@ -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;
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue