removed some deprecated code from bigint.c

fixed a bigint division bug when MOO_USE_FULL_WORD is undefined
This commit is contained in:
hyunghwan.chung 2019-04-01 08:45:21 +00:00
parent 8ce908262a
commit f28bd84c50
2 changed files with 86 additions and 221 deletions

View File

@ -317,6 +317,13 @@ extend MyObject
## 135-139 ## 135-139
[ (-65535 rem: 8113063330913503995887611892379812731289731289312898971231) = -65535 ], [ (-65535 rem: 8113063330913503995887611892379812731289731289312898971231) = -65535 ],
[ (-65535 mod: 8113063330913503995887611892379812731289731289312898971231) = 8113063330913503995887611892379812731289731289312898905696 ], [ (-65535 mod: 8113063330913503995887611892379812731289731289312898971231) = 8113063330913503995887611892379812731289731289312898905696 ],
[ (8113063330913503995887611892379812731289731289312898971231 div: 34359738368) = 236121219667649827777862429280643489074710852271 ],
[ (-8113063330913503995887611892379812731289731289312898971231 div: 34359738368) = -236121219667649827777862429280643489074710852271 ],
[ (-8113063330913503995887611892379812731289731289312898971231 mdiv: 34359738368) = -236121219667649827777862429280643489074710852272 ],
## 140-144
[ (-8113063330913503995887611892379812731289731289312898971231 rem: 34359738368) = -31040337503 ],
[ (-8113063330913503995887611892379812731289731289312898971231 mod: 34359738368) = 3319400865 ],
## ========================= ## =========================
[ [

View File

@ -1592,24 +1592,54 @@ static void divide_unsigned_array (moo_t* moo, const moo_liw_t* x, moo_oow_t xs,
#if 0 #if 0
static void divide_unsigned_array2 (moo_t* moo, const moo_liw_t* x, moo_oow_t xs, const moo_liw_t* y, moo_oow_t ys, moo_liw_t* q, moo_liw_t* r) static void divide_unsigned_array2 (moo_t* moo, const moo_liw_t* x, moo_oow_t xs, const moo_liw_t* y, moo_oow_t ys, moo_liw_t* q, moo_liw_t* r)
{ {
moo_oow_t rsize, qsize; moo_oow_t i;
/* estimate result sizes */ d = (y[ys - 1] == MOO_TYPE_MAX(moo_liw_t)? 1: (((moo_lidw_t)1 << MOO_LIW_BITS) / (y[ys - 1] + 1));
rsize = ys; if (d > 1)
qsize = xs - ys + 1;
npos = xs - 1;
dpos = ys - 1;
for (j = qsize - 1; j >= 0; j--, npos--)
{ {
if (ndigs[npos] == ddigs[dpos] x[xs] = multiply_unsigned_array_in_place_and_get_last_carry(x, xs, d);
carry = multiply_unsigned_array_in_place_and_get_last_carry(y, ys, d); /* carry must be zero */
MOO_ASSERT (moo, carry == 0);
}
for (i = xs; i >= ys; )
{
moo_liw_t q;
moo_liw_t y1, y2;
y1 = y[ys - 1];
y2 = y[ys - 2];
if (x[i] == y1)
{
q = MOO_TYPE_MAX(moo_liw_t);
}
else else
{
moo_lidw_t dw;
carry = scarry = 0; dw = ((moo_lidw_t)x[i] << MOO_LIW_BITS) + x[i - 1];
/* TODO: optimize it with ASM - no seperate / and % */
q = dw / y1;
x[i] = dw % y1;
}
qdigs[j] = qest; while (i < ys) { j++; k++; }
x[i] = q;
i--;
}
if (d != 1)
{
moo_lidw_t dw;
moo_liw_t carry = 0;
for (i = ys; i > 0; )
{
--i;
dw = ((moo_lidw_t)x[i] << MOO_LIW_BITS) + carry;
/* TODO: optimize it with ASM - no seperate / and % */
x[i] = dw / y1;
carry = dw % y1;
}
} }
} }
#endif #endif
@ -1706,6 +1736,25 @@ static moo_oop_t multiply_unsigned_integers (moo_t* moo, moo_oop_t x, moo_oop_t
return z; return z;
} }
static moo_liw_t multiply_unsigned_array_in_place_and_get_last_carry (moo_liw_t* x, moo_oow_t xs, moo_liw_t y)
{
/* multiply unsigned array with a single word and put the result
* back to the array. return the last remaining carry */
moo_lidw_t dw;
moo_liw_t carry = 0;
moo_oow_t i;
for (i = 0; i < xs; i++)
{
dw = ((moo_lidw_t)x[i] * y) + carry;
carry = (moo_liw_t)(dw >> MOO_LIW_BITS);
x[i] = (moo_liw_t)dw/*& MOO_TYPE_MAX(moo_liw_t)*/;
}
return carry;
}
static moo_oop_t divide_unsigned_integers (moo_t* moo, moo_oop_t x, moo_oop_t y, moo_oop_t* r) static moo_oop_t divide_unsigned_integers (moo_t* moo, moo_oop_t x, moo_oop_t y, moo_oop_t* r)
{ {
moo_oop_t qq, rr; moo_oop_t qq, rr;
@ -1960,7 +2009,7 @@ moo_oop_t moo_mulints (moo_t* moo, moo_oop_t x, moo_oop_t y)
if (MOO_OOP_IS_SMOOI(x) && MOO_OOP_IS_SMOOI(y)) if (MOO_OOP_IS_SMOOI(x) && MOO_OOP_IS_SMOOI(y))
{ {
#if MOO_SIZEOF_INTMAX_T > MOO_SIZEOF_OOI_T #if (MOO_SIZEOF_INTMAX_T > MOO_SIZEOF_OOI_T)
moo_intmax_t i; moo_intmax_t i;
i = (moo_intmax_t)MOO_OOP_TO_SMOOI(x) * (moo_intmax_t)MOO_OOP_TO_SMOOI(y); i = (moo_intmax_t)MOO_OOP_TO_SMOOI(x) * (moo_intmax_t)MOO_OOP_TO_SMOOI(y);
if (MOO_IN_SMOOI_RANGE(i)) return MOO_SMOOI_TO_OOP((moo_ooi_t)i); if (MOO_IN_SMOOI_RANGE(i)) return MOO_SMOOI_TO_OOP((moo_ooi_t)i);
@ -1985,7 +2034,7 @@ moo_oop_t moo_mulints (moo_t* moo, moo_oop_t x, moo_oop_t y)
moo_popvolat (moo); moo_popvolat (moo);
if (!y) return MOO_NULL; if (!y) return MOO_NULL;
goto normal; goto full_multiply;
} }
else else
{ {
@ -2045,7 +2094,7 @@ moo_oop_t moo_mulints (moo_t* moo, moo_oop_t x, moo_oop_t y)
if (!is_bigint(moo,y)) goto oops_einval; if (!is_bigint(moo,y)) goto oops_einval;
} }
normal: full_multiply:
neg = (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)); /* checking sign before multication. no need to preserve x and y */ neg = (MOO_OBJ_GET_CLASS(x) != MOO_OBJ_GET_CLASS(y)); /* checking sign before multication. no need to preserve x and y */
z = multiply_unsigned_integers(moo, x, y); z = multiply_unsigned_integers(moo, x, y);
if (!z) return MOO_NULL; if (!z) return MOO_NULL;
@ -2174,20 +2223,26 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
if (!is_bigint(moo,y)) goto oops_einval; if (!is_bigint(moo,y)) goto oops_einval;
/* divide a small integer by a big integer.
* the dividend is guaranteed to be greater than the divisor
* if both are positive. */
xv = MOO_OOP_TO_SMOOI(x); xv = MOO_OOP_TO_SMOOI(x);
x_neg_sign = (xv < 0); x_neg_sign = (xv < 0);
y_neg_sign = MOO_POINTER_IS_NBIGINT(moo, y); y_neg_sign = MOO_POINTER_IS_NBIGINT(moo, y);
if (x_neg_sign == y_neg_sign || !modulo) if (x_neg_sign == y_neg_sign || !modulo)
{ {
/* simple. the quotient is zero and the
* dividend becomes the remainder as a whole. */
if (rem) *rem = x; if (rem) *rem = x;
return MOO_SMOOI_TO_OOP(0); return MOO_SMOOI_TO_OOP(0);
} }
/* carry on to the full bigint division */
moo_pushvolat (moo, &y); moo_pushvolat (moo, &y);
x = make_bigint_with_ooi(moo, xv); x = make_bigint_with_ooi(moo, xv);
moo_popvolat (moo); moo_popvolat (moo);
if (!x) return MOO_NULL; if (!x) return MOO_NULL;
/* carry on the the full division */
} }
else if (MOO_OOP_IS_SMOOI(y)) else if (MOO_OOP_IS_SMOOI(y))
{ {
@ -2195,6 +2250,8 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
if (!is_bigint(moo,x)) goto oops_einval; if (!is_bigint(moo,x)) goto oops_einval;
/* divide a big integer by a small integer. */
yv = MOO_OOP_TO_SMOOI(y); yv = MOO_OOP_TO_SMOOI(y);
switch (yv) switch (yv)
{ {
@ -2208,7 +2265,6 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
if (rem) *rem = MOO_SMOOI_TO_OOP(0); if (rem) *rem = MOO_SMOOI_TO_OOP(0);
return z; return z;
case -1: /* divide by -1 */ case -1: /* divide by -1 */
z = clone_bigint_negated(moo, x, MOO_OBJ_GET_SIZE(x)); z = clone_bigint_negated(moo, x, MOO_OBJ_GET_SIZE(x));
if (!z) return MOO_NULL; if (!z) return MOO_NULL;
@ -2224,6 +2280,10 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
moo_ooi_t yv_abs, ri; moo_ooi_t yv_abs, ri;
yv_abs = (yv < 0)? -yv: yv; yv_abs = (yv < 0)? -yv: yv;
#if (MOO_LIW_BITS < MOO_OOI_BITS)
if (yv_abs > MOO_TYPE_MAX(moo_liw_t)) break;
#endif
x_neg_sign = (MOO_POINTER_IS_NBIGINT(moo, x)); x_neg_sign = (MOO_POINTER_IS_NBIGINT(moo, x));
y_neg_sign = (yv < 0); y_neg_sign = (yv < 0);
@ -2273,6 +2333,7 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
} }
} }
/* carry on to the full bigint division */
moo_pushvolat (moo, &x); moo_pushvolat (moo, &x);
y = make_bigint_with_ooi(moo, yv); y = make_bigint_with_ooi(moo, yv);
moo_popvolat (moo); moo_popvolat (moo);
@ -4278,20 +4339,6 @@ moo_oop_t moo_absint (moo_t* moo, moo_oop_t x)
return x; return x;
} }
static MOO_INLINE moo_liw_t div_with_carry (moo_liw_t x, moo_liw_t y, moo_liw_t* r)
{
/* TODO: optimize it with ASM */
moo_liw_t q;
moo_lidw_t dd;
dd = ((moo_lidw_t)*r << MOO_LIW_BITS) + x;
q = dd / y;
*r = dd % y;
return q;
}
static MOO_INLINE moo_liw_t get_last_digit (moo_t* moo, moo_liw_t* x, moo_oow_t* xs, int radix) static MOO_INLINE moo_liw_t get_last_digit (moo_t* moo, moo_liw_t* x, moo_oow_t* xs, int radix)
{ {
/* this function changes the contents of the large integer word array */ /* this function changes the contents of the large integer word array */
@ -4305,40 +4352,20 @@ static MOO_INLINE moo_liw_t get_last_digit (moo_t* moo, moo_liw_t* x, moo_oow_t*
for (i = oxs; i > 0; ) for (i = oxs; i > 0; )
{ {
--i; --i;
#if 0
x[i] = div_with_carry(x[i], radix, &carry);
#else
dw = ((moo_lidw_t)carry << MOO_LIW_BITS) + x[i]; dw = ((moo_lidw_t)carry << MOO_LIW_BITS) + x[i];
/* TODO: optimize it with ASM - no seperate / and % */ /* TODO: optimize it with ASM - no seperate / and % */
x[i] = dw / radix; x[i] = dw / radix;
carry = dw % radix; carry = dw % radix;
#endif
} }
if (/*oxs > 0 &&*/ x[oxs - 1] == 0) *xs = oxs - 1; if (/*oxs > 0 &&*/ x[oxs - 1] == 0) *xs = oxs - 1;
return carry; return carry;
} }
moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int flagged_radix) moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int flagged_radix)
{ {
moo_ooi_t v = 0; moo_ooi_t v = 0;
moo_oow_t w; moo_oow_t w;
moo_oow_t as; moo_oow_t as;
/*#define INTTOSTR_SLOW_WORD_BY_WORD_CONVERSION*/
#if defined(INTTOSTR_SLOW_WORD_BY_WORD_CONVERSION)
moo_oow_t bs, rs;
#if (MOO_LIW_BITS == MOO_OOW_BITS)
moo_liw_t b[1];
#elif (MOO_LIW_BITS == MOO_OOHW_BITS)
moo_liw_t b[2];
#else
# error UNSUPPORTED LIW BIT SIZE
#endif
moo_liw_t* a, * q, * r;
#endif
moo_liw_t* t = MOO_NULL; moo_liw_t* t = MOO_NULL;
moo_ooch_t* xbuf = MOO_NULL; moo_ooch_t* xbuf = MOO_NULL;
moo_oow_t xlen = 0, reqcapa; moo_oow_t xlen = 0, reqcapa;
@ -4389,174 +4416,6 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int flagged_radix)
as = MOO_OBJ_GET_SIZE(num); as = MOO_OBJ_GET_SIZE(num);
#if defined(INTTOSTR_SLOW_WORD_BY_WORD_CONVERSION)
if (IS_POW2(radix))
{
unsigned int exp, accbits;
moo_lidw_t acc;
moo_oow_t xpos;
/*exp = LOG2_FOR_POW2(radix);*/
exp = _exp_tab[radix - 1];
xlen = as * ((MOO_LIW_BITS + exp) / exp) + 1;
xpos = xlen;
reqcapa = xlen;
if (moo->inttostr.xbuf.capa < reqcapa)
{
xbuf = (moo_ooch_t*)moo_reallocmem(moo, moo->inttostr.xbuf.ptr, reqcapa * MOO_SIZEOF(*xbuf));
if (!xbuf) return MOO_NULL;
moo->inttostr.xbuf.capa = reqcapa;
moo->inttostr.xbuf.ptr = xbuf;
}
else
{
xbuf = moo->inttostr.xbuf.ptr;
}
acc = 0;
accbits = 0;
w = 0;
while (w < as)
{
acc |= (moo_lidw_t)MOO_OBJ_GET_LIWORD_SLOT(num)[w] << accbits;
accbits += MOO_LIW_BITS;
w++;
do
{
xbuf[--xpos] = _digitc[acc & (radix - 1)]; /* acc % radix */
accbits -= exp;
acc >>= exp;
if (w < as)
{
if (accbits < exp) break;
}
else
{
if (acc <= 0) break;
}
}
while (1);
}
MOO_ASSERT (moo, xpos >= 1);
if (MOO_POINTER_IS_NBIGINT(moo, num)) xbuf[--xpos] = '-';
if (flagged_radix & MOO_INTTOSTR_NONEWOBJ)
{
/* special case. don't create a new object.
* the caller can use the data left in moo->inttostr.xbuf */
MOO_MEMMOVE (&xbuf[0], &xbuf[xpos], MOO_SIZEOF(*xbuf) * (xlen - xpos));
moo->inttostr.xbuf.len = xlen - xpos;
return moo->_nil;
}
return moo_makestring(moo, &xbuf[xpos], xlen - xpos);
}
/* Do it in a hard way for other cases */
/* TODO: find an optimial buffer size */
reqcapa = as * MOO_LIW_BITS + 1;
if (moo->inttostr.xbuf.capa < reqcapa)
{
xbuf = (moo_ooch_t*)moo_reallocmem(moo, moo->inttostr.xbuf.ptr, reqcapa * MOO_SIZEOF(*xbuf));
if (!xbuf) return MOO_NULL;
moo->inttostr.xbuf.capa = reqcapa;
moo->inttostr.xbuf.ptr = xbuf;
}
else
{
xbuf = moo->inttostr.xbuf.ptr;
}
reqcapa = as * 3;
if (moo->inttostr.t.capa < reqcapa)
{
t = (moo_liw_t*)moo_reallocmem(moo, moo->inttostr.t.ptr, reqcapa * MOO_SIZEOF(*t));
if (!t) return MOO_NULL;
moo->inttostr.t.capa = reqcapa;
moo->inttostr.t.ptr = t;
}
else
{
t = moo->inttostr.t.ptr;
}
#if (MOO_LIW_BITS == MOO_OOW_BITS)
b[0] = moo->bigint[radix].multiplier; /* block divisor */
bs = 1;
#elif (MOO_LIW_BITS == MOO_OOHW_BITS)
b[0] = moo->bigint[radix].multiplier /*& MOO_LBMASK(moo_oow_t, MOO_LIW_BITS)*/;
b[1] = moo->bigint[radix].multiplier >> MOO_LIW_BITS;
bs = (b[1] > 0)? 2: 1;
#else
# error UNSUPPORTED LIW BIT SIZE
#endif
a = &t[0]; /* temporary space for the number to convert */
q = &t[as]; /* temporary space for intermediate quotient */
r = &t[as * 2]; /* temporary space for intermediate remainder */
MOO_MEMCPY (a, MOO_OBJ_GET_LIWORD_SLOT(num), MOO_SIZEOF(*a) * as);
do
{
moo_oow_t seglen;
/* NOTE: this loop is super-slow */
if (is_less_unsigned_array(b, bs, a, as))
{
moo_liw_t* tmp;
divide_unsigned_array(moo, a, as, b, bs, q, r);
/* get 'rs' before 'as' gets changed */
rs = count_effective(r, as);
/* swap a and q for later division */
tmp = a;
a = q;
q = tmp;
as = count_effective(a, as);
}
else
{
/* it is the last block */
r = a;
rs = as;
}
#if (MOO_LIW_BITS == MOO_OOW_BITS)
MOO_ASSERT (moo, rs == 1);
w = r[0];
#elif (MOO_LIW_BITS == MOO_OOHW_BITS)
if (rs == 1) w = r[0];
else
{
MOO_ASSERT (moo, rs == 2);
w = MAKE_WORD(r[0], r[1]);
}
#else
# error UNSUPPORTED LIW BIT SIZE
#endif
seglen = oow_to_text(moo, w, flagged_radix, &xbuf[xlen]);
xlen += seglen;
if (r == a) break; /* reached the last block */
/* fill unfilled leading digits with zeros as it's not
* the last block */
while (seglen < moo->bigint[radix].safe_ndigits)
{
xbuf[xlen++] = '0';
seglen++;
}
}
while (1);
#else
reqcapa = as * MOO_LIW_BITS + 1; reqcapa = as * MOO_LIW_BITS + 1;
if (moo->inttostr.xbuf.capa < reqcapa) if (moo->inttostr.xbuf.capa < reqcapa)
{ {
@ -4590,7 +4449,6 @@ moo_oop_t moo_inttostr (moo_t* moo, moo_oop_t num, int flagged_radix)
xbuf[xlen++] = _digitc[dv]; xbuf[xlen++] = _digitc[dv];
} }
while (as > 0); while (as > 0);
#endif
if (MOO_POINTER_IS_NBIGINT(moo, num)) xbuf[xlen++] = '-'; if (MOO_POINTER_IS_NBIGINT(moo, num)) xbuf[xlen++] = '-';
reverse_string (xbuf, xlen); reverse_string (xbuf, xlen);