factor/native/fixnum.c

194 lines
3.0 KiB
C
Raw Normal View History

2004-07-16 02:26:21 -04:00
#include "factor.h"
void primitive_fixnump(void)
{
drepl(tag_boolean(TAG(dpeek()) == FIXNUM_TYPE));
2004-07-16 02:26:21 -04:00
}
2004-08-05 15:18:31 -04:00
FIXNUM to_fixnum(CELL tagged)
{
RATIO* r;
2004-08-05 16:49:55 -04:00
FLOAT* f;
2004-08-05 15:18:31 -04:00
switch(type_of(tagged))
{
case FIXNUM_TYPE:
return untag_fixnum_fast(tagged);
case BIGNUM_TYPE:
return bignum_to_fixnum(tagged);
case RATIO_TYPE:
r = (RATIO*)UNTAG(tagged);
return to_fixnum(divint(r->numerator,r->denominator));
2004-08-05 16:49:55 -04:00
case FLOAT_TYPE:
f = (FLOAT*)UNTAG(tagged);
return (FIXNUM)f->n;
2004-08-05 15:18:31 -04:00
default:
type_error(FIXNUM_TYPE,tagged);
return -1; /* can't happen */
}
}
void primitive_to_fixnum(void)
{
drepl(tag_fixnum(to_fixnum(dpeek())));
2004-08-05 15:18:31 -04:00
}
CELL number_eq_fixnum(CELL x, CELL y)
{
return tag_boolean(x == y);
}
CELL add_fixnum(CELL x, CELL y)
{
CELL_TO_INTEGER(untag_fixnum_fast(x) + untag_fixnum_fast(y));
}
CELL subtract_fixnum(CELL x, CELL y)
{
CELL_TO_INTEGER(untag_fixnum_fast(x) - untag_fixnum_fast(y));
}
CELL multiply_fixnum(CELL x, CELL y)
{
BIGNUM_2_TO_INTEGER((BIGNUM_2)untag_fixnum_fast(x)
* (BIGNUM_2)untag_fixnum_fast(y));
}
CELL divint_fixnum(CELL x, CELL y)
{
/* division takes common factor of 8 out. */
2004-08-05 16:49:55 -04:00
/* we have to do SIGNED division here */
return tag_fixnum((FIXNUM)x / (FIXNUM)y);
}
CELL divfloat_fixnum(CELL x, CELL y)
{
/* division takes common factor of 8 out. */
/* we have to do SIGNED division here */
FIXNUM _x = (FIXNUM)x;
FIXNUM _y = (FIXNUM)y;
return tag_object(make_float((double)_x / (double)_y));
2004-08-05 15:18:31 -04:00
}
CELL divmod_fixnum(CELL x, CELL y)
{
ldiv_t q = ldiv(x,y);
/* division takes common factor of 8 out. */
dpush(tag_fixnum(q.quot));
return q.rem;
}
CELL mod_fixnum(CELL x, CELL y)
{
return x % y;
}
FIXNUM gcd_fixnum(FIXNUM x, FIXNUM y)
{
FIXNUM t;
if(x < 0)
x = -x;
if(y < 0)
y = -y;
if(x > y)
{
t = x;
x = y;
y = t;
}
for(;;)
{
if(x == 0)
return y;
t = y % x;
y = x;
x = t;
}
}
CELL divide_fixnum(CELL x, CELL y)
{
FIXNUM _x = untag_fixnum_fast(x);
FIXNUM _y = untag_fixnum_fast(y);
2004-08-05 16:49:55 -04:00
FIXNUM gcd;
2004-08-05 15:18:31 -04:00
if(_y == 0)
{
/* FIXME */
abort();
}
else if(_y < 0)
{
_x = -_x;
_y = -_y;
}
2004-08-05 16:49:55 -04:00
gcd = gcd_fixnum(_x,_y);
2004-08-05 15:18:31 -04:00
if(gcd != 1)
{
_x /= gcd;
_y /= gcd;
}
if(_y == 1)
return tag_fixnum(_x);
else
return tag_ratio(ratio(tag_fixnum(_x),tag_fixnum(_y)));
}
CELL and_fixnum(CELL x, CELL y)
{
return x & y;
}
CELL or_fixnum(CELL x, CELL y)
{
return x | y;
}
CELL xor_fixnum(CELL x, CELL y)
{
return x ^ y;
}
CELL shiftleft_fixnum(CELL x, CELL y)
{
BIGNUM_2_TO_INTEGER((BIGNUM_2)untag_fixnum_fast(x)
<< (BIGNUM_2)untag_fixnum_fast(y));
}
CELL shiftright_fixnum(CELL x, CELL y)
{
BIGNUM_2_TO_INTEGER((BIGNUM_2)untag_fixnum_fast(x)
>> (BIGNUM_2)untag_fixnum_fast(y));
}
CELL less_fixnum(CELL x, CELL y)
{
return tag_boolean((FIXNUM)x < (FIXNUM)y);
}
CELL lesseq_fixnum(CELL x, CELL y)
{
return tag_boolean((FIXNUM)x <= (FIXNUM)y);
}
CELL greater_fixnum(CELL x, CELL y)
{
return tag_boolean((FIXNUM)x > (FIXNUM)y);
}
CELL greatereq_fixnum(CELL x, CELL y)
{
return tag_boolean((FIXNUM)x >= (FIXNUM)y);
}
2004-08-17 23:42:10 -04:00
CELL not_fixnum(CELL n)
{
return RETAG(UNTAG(~n),FIXNUM_TYPE);
}