enhanced moo_divints()

This commit is contained in:
hyunghwan.chung 2019-03-30 13:43:10 +00:00
parent 0480cba4ad
commit 8ce908262a
2 changed files with 68 additions and 106 deletions

View File

@ -300,6 +300,23 @@ extend MyObject
[ (-8113063330913503995887611892379812731289731289312898971231 rem: 65535) = -65231 ], [ (-8113063330913503995887611892379812731289731289312898971231 rem: 65535) = -65231 ],
[ (-8113063330913503995887611892379812731289731289312898971231 mod: 65535) = 304 ], [ (-8113063330913503995887611892379812731289731289312898971231 mod: 65535) = 304 ],
## 125-129
[ (65535 div: -8113063330913503995887611892379812731289731289312898971231) = 0 ],
[ (65535 mdiv: -8113063330913503995887611892379812731289731289312898971231) = -1 ],
[ (65535 rem: -8113063330913503995887611892379812731289731289312898971231) = 65535 ],
[ (65535 mod: -8113063330913503995887611892379812731289731289312898971231) = -8113063330913503995887611892379812731289731289312898905696 ],
[ (-65535 div: -8113063330913503995887611892379812731289731289312898971231) = 0 ],
## 130-134
[ (-65535 mdiv: -8113063330913503995887611892379812731289731289312898971231) = 0 ],
[ (-65535 rem: -8113063330913503995887611892379812731289731289312898971231) = -65535],
[ (-65535 mod: -8113063330913503995887611892379812731289731289312898971231) = -65535 ],
[ (-65535 div: 8113063330913503995887611892379812731289731289312898971231) = 0 ],
[ (-65535 mdiv: 8113063330913503995887611892379812731289731289312898971231) = -1 ],
## 135-139
[ (-65535 rem: 8113063330913503995887611892379812731289731289312898971231) = -65535 ],
[ (-65535 mod: 8113063330913503995887611892379812731289731289312898971231) = 8113063330913503995887611892379812731289731289312898905696 ],
## ========================= ## =========================
[ [

View File

@ -2062,7 +2062,7 @@ oops_einval:
moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop_t* rem) moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop_t* rem)
{ {
moo_oop_t z, r; moo_oop_t z, r;
int x_neg, y_neg; int x_neg_sign, y_neg_sign;
if (MOO_OOP_IS_SMOOI(x) && MOO_OOP_IS_SMOOI(y)) if (MOO_OOP_IS_SMOOI(x) && MOO_OOP_IS_SMOOI(y))
{ {
@ -2170,21 +2170,24 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
if (MOO_OOP_IS_SMOOI(x)) if (MOO_OOP_IS_SMOOI(x))
{ {
moo_ooi_t yv; moo_ooi_t xv;
if (!is_bigint(moo,y)) goto oops_einval; if (!is_bigint(moo,y)) goto oops_einval;
yv = MOO_OOP_TO_SMOOI(x); xv = MOO_OOP_TO_SMOOI(x);
if (yv == 0) x_neg_sign = (xv < 0);
y_neg_sign = MOO_POINTER_IS_NBIGINT(moo, y);
if (x_neg_sign == y_neg_sign || !modulo)
{ {
if (rem) *rem = MOO_SMOOI_TO_OOP(0); if (rem) *rem = x;
return MOO_SMOOI_TO_OOP(0); return MOO_SMOOI_TO_OOP(0);
} }
moo_pushvolat (moo, &y); moo_pushvolat (moo, &y);
x = make_bigint_with_ooi(moo, yv); 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))
{ {
@ -2213,15 +2216,18 @@ moo_oop_t moo_divints (moo_t* moo, moo_oop_t x, moo_oop_t y, int modulo, moo_oop
return z; return z;
default: default:
#if 0
TODO:
{ {
moo_lidw_t dw; moo_lidw_t dw;
moo_liw_t carry = 0; moo_liw_t carry = 0;
moo_liw_t* zw; moo_liw_t* zw;
moo_oow_t zs, i; moo_oow_t zs, i;
moo_ooi_t yv_abs, ri;
z = clone_bigint(moo, x, MOO_OBJ_GET_SIZE(x)); yv_abs = (yv < 0)? -yv: yv;
x_neg_sign = (MOO_POINTER_IS_NBIGINT(moo, x));
y_neg_sign = (yv < 0);
z = clone_bigint_to_positive(moo, x, MOO_OBJ_GET_SIZE(x));
if (!z) return MOO_NULL; if (!z) return MOO_NULL;
zw = MOO_OBJ_GET_LIWORD_SLOT(z); zw = MOO_OBJ_GET_LIWORD_SLOT(z);
@ -2231,103 +2237,41 @@ TODO:
--i; --i;
dw = ((moo_lidw_t)carry << MOO_LIW_BITS) + zw[i]; dw = ((moo_lidw_t)carry << MOO_LIW_BITS) + zw[i];
/* TODO: optimize it with ASM - no seperate / and % */ /* TODO: optimize it with ASM - no seperate / and % */
zw[i] = dw / yv; zw[i] = dw / yv_abs;
carry = dw % yv; carry = dw % yv_abs;
} }
if (zw[zs - 1] == 0) /*if (zw[zs - 1] == 0) zs--;*/
if (rem) *rem = MOO_SMOOI_TO_OOP(carry); MOO_ASSERT (moo, carry <= MOO_SMOOI_MAX);
return normalize_bigint(moo, z); ri = carry;
} if (x_neg_sign) ri = -ri;
#endif
/* TODO: do division by shifting if both x & y are in different sign */
if (yv < 0)
{
moo_oow_t yv_neg = -yv;
if (IS_POW2(yv_neg) && MOO_POINTER_IS_NBIGINT(moo, x))
{
moo_oow_t nshifts;
nshifts = LOG2_FOR_POW2(yv_neg);
moo_pushvolat (moo, &x);
z = clone_bigint_negated(moo, x, MOO_OBJ_GET_SIZE(x));
moo_popvolat (moo);
if (!z) return MOO_NULL;
rshift_unsigned_array (MOO_OBJ_GET_LIWORD_SLOT(z), MOO_OBJ_GET_SIZE(z), nshifts);
moo_pushvolat (moo, &x);
z = normalize_bigint(moo, z); z = normalize_bigint(moo, z);
moo_popvolat (moo);
if (!z) return MOO_NULL; if (!z) return MOO_NULL;
if (x_neg_sign != y_neg_sign)
{
MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer);
if (ri && modulo)
{
z = moo_subints(moo, z, MOO_SMOOI_TO_OOP(1));
if (!z) return MOO_NULL;
if (rem) if (rem)
{ {
moo_pushvolat (moo, &x);
moo_pushvolat (moo, &z); moo_pushvolat (moo, &z);
r = moo_mulints(moo, MOO_SMOOI_TO_OOP(yv_neg), z); r = moo_addints(moo, MOO_SMOOI_TO_OOP(ri), MOO_SMOOI_TO_OOP(yv));
moo_popvolats (moo, 2);
if (!r) return MOO_NULL;
moo_pushvolat (moo, &z);
r = moo_addints(moo, x, r);
moo_popvolat (moo); moo_popvolat (moo);
if (!r) return MOO_NULL; if (!r) return MOO_NULL;
*rem = r; *rem = r;
} }
return z; return z;
} }
} }
else
{
/* yv > 0 */
if (IS_POW2(yv) && MOO_POINTER_IS_PBIGINT(moo, x))
{
moo_oow_t nshifts;
/*
2**x = v
x = log2(v)
x is the number of shift to make */
nshifts = LOG2_FOR_POW2(yv);
/* no pushvolat() on y as y is SMOOI here */
moo_pushvolat (moo, &x);
z = clone_bigint(moo, x, MOO_OBJ_GET_SIZE(x));
moo_popvolat (moo);
if (!z) return MOO_NULL;
rshift_unsigned_array (MOO_OBJ_GET_LIWORD_SLOT(z), MOO_OBJ_GET_SIZE(z), nshifts);
moo_pushvolat (moo, &x);
z = normalize_bigint(moo, z);
moo_popvolat (moo);
if (!z) return MOO_NULL;
if (rem)
{
moo_pushvolat (moo, &x);
moo_pushvolat (moo, &z);
r = moo_mulints(moo, y, z);
moo_popvolats (moo, 2);
if (!r) return MOO_NULL;
moo_pushvolat (moo, &z);
r = moo_subints(moo, x, r);
moo_popvolat (moo);
if (!r) return MOO_NULL;
*rem = r;
}
if (rem) *rem = MOO_SMOOI_TO_OOP(ri);
return z; return z;
} }
} }
break;
}
moo_pushvolat (moo, &x); moo_pushvolat (moo, &x);
y = make_bigint_with_ooi(moo, yv); y = make_bigint_with_ooi(moo, yv);
@ -2341,8 +2285,8 @@ TODO:
} }
} }
x_neg = (MOO_POINTER_IS_NBIGINT(moo, x)); x_neg_sign = (MOO_POINTER_IS_NBIGINT(moo, x));
y_neg = (MOO_POINTER_IS_NBIGINT(moo, y)); y_neg_sign = (MOO_POINTER_IS_NBIGINT(moo, y));
moo_pushvolat (moo, &x); moo_pushvolat (moo, &x);
moo_pushvolat (moo, &y); moo_pushvolat (moo, &y);
@ -2350,14 +2294,15 @@ TODO:
moo_popvolats (moo, 2); moo_popvolats (moo, 2);
if (!z) return MOO_NULL; if (!z) return MOO_NULL;
if (x_neg) if (x_neg_sign)
{ {
/* the class on r must be set before normalize_bigint() /* the class on r must be set before normalize_bigint()
* because it can get changed to a small integer */ * because it can get changed to a small integer */
MOO_OBJ_SET_CLASS(r, moo->_large_negative_integer); MOO_OBJ_SET_CLASS(r, moo->_large_negative_integer);
} }
if (x_neg != y_neg) if (x_neg_sign != y_neg_sign)
{ {
MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer); MOO_OBJ_SET_CLASS(z, moo->_large_negative_integer);