added code to shift a large negative integer when STIX_LIMIT_OBJ_SIZE is not defined
This commit is contained in:
parent
2022ac965b
commit
1e7be310fc
@ -374,6 +374,9 @@ PROCESS TESTING
|
|||||||
((-2r11111111111111111111111111111111111111111111111111111111111111111111110001 bitShift: -3) printStringRadix: 2) dump.
|
((-2r11111111111111111111111111111111111111111111111111111111111111111111110001 bitShift: -3) printStringRadix: 2) dump.
|
||||||
((-2r11111111111111111111111111111111111111111111111111111111111111111111110001 bitShift: -200) printStringRadix: 2) dump.
|
((-2r11111111111111111111111111111111111111111111111111111111111111111111110001 bitShift: -200) printStringRadix: 2) dump.
|
||||||
((-2r1000000000000000000000000000100000000000000000000000000000000000000000000000 bitShift: -5) printStringRadix: 2) dump.
|
((-2r1000000000000000000000000000100000000000000000000000000000000000000000000000 bitShift: -5) printStringRadix: 2) dump.
|
||||||
|
((-2r1000000000000000000000000000100000000000000000000000000000000000000000000000 bitShift: -16rFFFFFFFFFFFFFFFF) printStringRadix: 2) dump.
|
||||||
|
((-2r1000000000000000000000000000100000000000000000000000000000000000000000000000 bitShift: 13) printStringRadix: 2) dump.
|
||||||
|
((2r1000000000000000000000000000100000000000000000000000000000000000000000000000 bitShift: 13) printStringRadix: 2) dump.
|
||||||
|
|
||||||
|
|
||||||
"
|
"
|
||||||
|
@ -165,26 +165,73 @@ static STIX_INLINE int liw_mul_overflow (stix_liw_t a, stix_liw_t b, stix_liw_t*
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static STIX_INLINE int is_integer (stix_t* stix, stix_oop_t oop)
|
static int is_normalized_integer (stix_t* stix, stix_oop_t oop)
|
||||||
{
|
{
|
||||||
stix_oop_t c;
|
if (STIX_OOP_IS_SMOOI(oop)) return 1;
|
||||||
|
if (STIX_OOP_IS_POINTER(oop))
|
||||||
c = STIX_CLASSOF(stix,oop);
|
{
|
||||||
|
stix_oop_t c;
|
||||||
/* TODO: is it better to introduce a special integer mark into the class itself */
|
/* TODO: is it better to introduce a special integer mark into the class itself */
|
||||||
/* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */
|
/* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */
|
||||||
return c == stix->_small_integer ||
|
c = STIX_OBJ_GET_CLASS(oop);
|
||||||
c == stix->_large_positive_integer ||
|
|
||||||
c == stix->_large_negative_integer;
|
if (c == stix->_large_positive_integer ||
|
||||||
|
c == stix->_large_negative_integer)
|
||||||
|
{
|
||||||
|
stix_oow_t sz;
|
||||||
|
|
||||||
|
sz = STIX_OBJ_GET_SIZE(oop);
|
||||||
|
STIX_ASSERT (sz >= 1);
|
||||||
|
|
||||||
|
return ((stix_oop_liword_t)oop)->slot[sz - 1] == 0? 0: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static STIX_INLINE int bigint_to_oow (stix_t* stix, stix_oop_t num, stix_oow_t* w)
|
static STIX_INLINE int is_integer (stix_t* stix, stix_oop_t oop)
|
||||||
|
{
|
||||||
|
if (STIX_OOP_IS_SMOOI(oop)) return 1;
|
||||||
|
if (STIX_OOP_IS_POINTER(oop))
|
||||||
|
{
|
||||||
|
stix_oop_t c;
|
||||||
|
/* TODO: is it better to introduce a special integer mark into the class itself */
|
||||||
|
/* TODO: or should it check if it's a subclass, subsubclass, subsubsubclass, etc of a large_integer as well? */
|
||||||
|
c = STIX_OBJ_GET_CLASS(oop);
|
||||||
|
|
||||||
|
if (c == stix->_large_positive_integer ||
|
||||||
|
c == stix->_large_negative_integer) return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STIX_INLINE int integer_to_oow (stix_t* stix, stix_oop_t num, stix_oow_t* w)
|
||||||
{
|
{
|
||||||
/* return value
|
/* return value
|
||||||
* 1 - a positive number including 0 that can fit into stix_oow_t
|
* 1 - a positive number including 0 that can fit into stix_oow_t
|
||||||
* -1 - a negative number whose absolute value can fit into stix_oow_t
|
* -1 - a negative number whose absolute value can fit into stix_oow_t
|
||||||
* 0 - number too large or too small
|
* 0 - number too large or too small
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
if (STIX_OOP_IS_SMOOI(num))
|
||||||
|
{
|
||||||
|
stix_ooi_t v;
|
||||||
|
|
||||||
|
v = STIX_OOP_TO_SMOOI(num);
|
||||||
|
if (v < 0)
|
||||||
|
{
|
||||||
|
*w = -v;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*w = v;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#if (STIX_LIW_BITS == STIX_OOW_BITS)
|
#if (STIX_LIW_BITS == STIX_OOW_BITS)
|
||||||
STIX_ASSERT (STIX_OBJ_GET_SIZE(num) >= 1);
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(num) >= 1);
|
||||||
if (STIX_OBJ_GET_SIZE(num) == 1)
|
if (STIX_OBJ_GET_SIZE(num) == 1)
|
||||||
@ -194,6 +241,11 @@ static STIX_INLINE int bigint_to_oow (stix_t* stix, stix_oop_t num, stix_oow_t*
|
|||||||
}
|
}
|
||||||
|
|
||||||
#elif (STIX_LIW_BITS == STIX_OOHW_BITS)
|
#elif (STIX_LIW_BITS == STIX_OOHW_BITS)
|
||||||
|
/* this function must be called with a real large integer.
|
||||||
|
* a real large integer is at least 2 half-word long.
|
||||||
|
* you must not call this function with an unnormalized
|
||||||
|
* large integer. */
|
||||||
|
|
||||||
STIX_ASSERT (STIX_OBJ_GET_SIZE(num) >= 2);
|
STIX_ASSERT (STIX_OBJ_GET_SIZE(num) >= 2);
|
||||||
if (STIX_OBJ_GET_SIZE(num) == 2)
|
if (STIX_OBJ_GET_SIZE(num) == 2)
|
||||||
{
|
{
|
||||||
@ -2264,6 +2316,260 @@ oops_einval:
|
|||||||
return STIX_NULL;
|
return STIX_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static STIX_INLINE stix_oop_t rshift_negative_bigint (stix_t* stix, stix_oop_t x, stix_oow_t shift)
|
||||||
|
{
|
||||||
|
stix_oop_t z;
|
||||||
|
stix_lidw_t w;
|
||||||
|
stix_lidw_t carry;
|
||||||
|
stix_oow_t i, xs;
|
||||||
|
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(x) == stix->_large_negative_integer);
|
||||||
|
xs = STIX_OBJ_GET_SIZE(x);
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &x);
|
||||||
|
/* +1 for the second inversion below */
|
||||||
|
z = stix_instantiate (stix, stix->_large_negative_integer, STIX_NULL, xs + 1);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
|
/* the following lines roughly for 'z = stix_bitinv (stix, x)' */
|
||||||
|
carry = 1;
|
||||||
|
for (i = 0; i < xs; i++)
|
||||||
|
{
|
||||||
|
w = (stix_lidw_t)((stix_liw_t)~((stix_oop_liword_t)x)->slot[i]) + carry;
|
||||||
|
carry = w >> STIX_LIW_BITS;
|
||||||
|
((stix_oop_liword_t)z)->slot[i] = ~(stix_liw_t)w;
|
||||||
|
}
|
||||||
|
STIX_ASSERT (carry == 0);
|
||||||
|
|
||||||
|
/* shift to the right */
|
||||||
|
rshift_unsigned_array (((stix_oop_liword_t)z)->slot, xs, shift);
|
||||||
|
|
||||||
|
/* the following lines roughly for 'z = stix_bitinv (stix, z)' */
|
||||||
|
#if 0
|
||||||
|
for (i = 0; i < xs; i++)
|
||||||
|
{
|
||||||
|
((stix_oop_liword_t)z)->slot[i] = ~((stix_oop_liword_t)z)->slot[i];
|
||||||
|
}
|
||||||
|
((stix_oop_liword_t)z)->slot[xs] = ~(stix_liw_t)0;
|
||||||
|
|
||||||
|
carry = 1;
|
||||||
|
for (i = 0; i <= xs; i++)
|
||||||
|
{
|
||||||
|
w = (stix_lidw_t)((stix_liw_t)~((stix_oop_liword_t)z)->slot[i]) + carry;
|
||||||
|
carry = w >> STIX_LIW_BITS;
|
||||||
|
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)w;
|
||||||
|
}
|
||||||
|
STIX_ASSERT (carry == 0);
|
||||||
|
#else
|
||||||
|
carry = 1;
|
||||||
|
for (i = 0; i < xs; i++)
|
||||||
|
{
|
||||||
|
w = (stix_lidw_t)(((stix_oop_liword_t)z)->slot[i]) + carry;
|
||||||
|
carry = w >> STIX_LIW_BITS;
|
||||||
|
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)w;
|
||||||
|
}
|
||||||
|
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)carry;
|
||||||
|
STIX_ASSERT ((carry >> STIX_LIW_BITS) == 0);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return z; /* z is not normalized */
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(STIX_LIMIT_OBJ_SIZE)
|
||||||
|
/* nothing */
|
||||||
|
#else
|
||||||
|
|
||||||
|
static STIX_INLINE stix_oop_t rshift_negative_bigint_and_normalize (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
||||||
|
{
|
||||||
|
stix_oop_t z;
|
||||||
|
stix_oow_t shift;
|
||||||
|
int sign;
|
||||||
|
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(x) == stix->_large_negative_integer);
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer);
|
||||||
|
|
||||||
|
/* for convenience in subtraction below.
|
||||||
|
* it could be STIX_TYPE_MAX(stix_oow_t)
|
||||||
|
* if make_bigint_with_intmax() or something
|
||||||
|
* similar were used instead of STIX_SMOOI_TO_OOP().*/
|
||||||
|
shift = STIX_SMOOI_MAX;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
z = rshift_negative_bigint (stix, x, shift);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
|
/* y is a negative number. use stix_addints() until it becomes 0 */
|
||||||
|
stix_pushtmp (stix, &z);
|
||||||
|
y = stix_addints (stix, y, STIX_SMOOI_TO_OOP(shift));
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!y) return STIX_NULL;
|
||||||
|
|
||||||
|
sign = integer_to_oow (stix, y, &shift);
|
||||||
|
if (sign == 0) shift = STIX_SMOOI_MAX;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shift == 0)
|
||||||
|
{
|
||||||
|
/* no more shift */
|
||||||
|
return normalize_bigint (stix, z);
|
||||||
|
}
|
||||||
|
STIX_ASSERT (sign <= -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
x = normalize_bigint (stix, z);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!x) return STIX_NULL;
|
||||||
|
|
||||||
|
if (STIX_OOP_IS_SMOOI(x))
|
||||||
|
{
|
||||||
|
/* for normaization above, x can become a small integer */
|
||||||
|
stix_ooi_t v;
|
||||||
|
|
||||||
|
v = STIX_OOP_TO_SMOOI(x);
|
||||||
|
STIX_ASSERT (v < 0);
|
||||||
|
|
||||||
|
/* normal right shift of a small negative integer */
|
||||||
|
if (shift >= STIX_OOI_BITS - 1)
|
||||||
|
{
|
||||||
|
/* when y is still a large integer, this condition is met
|
||||||
|
* met as STIX_SMOOI_MAX > STIX_OOI_BITS. so i can simly
|
||||||
|
* terminate the loop after this */
|
||||||
|
return STIX_SMOOI_TO_OOP(-1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v = (stix_ooi_t)(((stix_oow_t)v >> shift) | STIX_HBMASK(stix_oow_t, shift));
|
||||||
|
if (STIX_IN_SMOOI_RANGE(v))
|
||||||
|
return STIX_SMOOI_TO_OOP(v);
|
||||||
|
else
|
||||||
|
return make_bigint_with_ooi (stix, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1);
|
||||||
|
|
||||||
|
/* this part must not be reached */
|
||||||
|
STIX_ASSERT (!"internal error - must not happen");
|
||||||
|
stix->errnum = STIX_EINTERN;
|
||||||
|
return STIX_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
static STIX_INLINE stix_oop_t rshift_positive_bigint_and_normalize (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
||||||
|
{
|
||||||
|
stix_oop_t z;
|
||||||
|
stix_oow_t zs, shift;
|
||||||
|
int sign;
|
||||||
|
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(x) == stix->_large_positive_integer);
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer);
|
||||||
|
|
||||||
|
zs = STIX_OBJ_GET_SIZE(x);
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
z = clone_bigint (stix, x, zs);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
|
/* for convenience in subtraction below.
|
||||||
|
* it could be STIX_TYPE_MAX(stix_oow_t)
|
||||||
|
* if make_bigint_with_intmax() or something
|
||||||
|
* similar were used instead of STIX_SMOOI_TO_OOP().*/
|
||||||
|
shift = STIX_SMOOI_MAX;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
rshift_unsigned_array (((stix_oop_liword_t)z)->slot, zs, shift);
|
||||||
|
if (count_effective (((stix_oop_liword_t)z)->slot, zs) == 1 &&
|
||||||
|
((stix_oop_liword_t)z)->slot[0] == 0)
|
||||||
|
{
|
||||||
|
/* if z is 0, i don't have to go on */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* y is a negative number. use stix_addints() until it becomes 0 */
|
||||||
|
stix_pushtmp (stix, &z);
|
||||||
|
y = stix_addints (stix, y, STIX_SMOOI_TO_OOP(shift));
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!y) return STIX_NULL;
|
||||||
|
|
||||||
|
sign = integer_to_oow (stix, y, &shift);
|
||||||
|
if (sign == 0) shift = STIX_SMOOI_MAX;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shift == 0) break;
|
||||||
|
STIX_ASSERT (sign <= -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1);
|
||||||
|
|
||||||
|
return normalize_bigint(stix, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
static STIX_INLINE stix_oop_t lshift_bigint_and_normalize (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
||||||
|
{
|
||||||
|
stix_oop_t z;
|
||||||
|
stix_oow_t wshift, shift;
|
||||||
|
int sign;
|
||||||
|
|
||||||
|
STIX_ASSERT (STIX_OBJ_GET_CLASS(y) == stix->_large_positive_integer);
|
||||||
|
|
||||||
|
/* this loop is very inefficient as shifting is repeated
|
||||||
|
* with lshift_unsigned_array(). however, this part of the
|
||||||
|
* code is not likey to be useful because the amount of
|
||||||
|
* memory available is certainly not enough to support
|
||||||
|
* huge shifts greater than STIX_TYPE_MAX(stix_oow_t) */
|
||||||
|
shift = STIX_SMOOI_MAX;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
/* for convenience only in subtraction below.
|
||||||
|
* should it be between STIX_SMOOI_MAX and STIX_TYPE_MAX(stix_oow_t),
|
||||||
|
* the second parameter to stix_subints() can't be composed
|
||||||
|
* using STIX_SMOOI_TO_OOP() */
|
||||||
|
wshift = shift / STIX_LIW_BITS;
|
||||||
|
if (shift > wshift * STIX_LIW_BITS) wshift++;
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
z = expand_bigint (stix, x, wshift);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
|
lshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
x = normalize_bigint (stix, z);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!x) return STIX_NULL;
|
||||||
|
|
||||||
|
stix_pushtmp (stix, &x);
|
||||||
|
y = stix_subints (stix, y, STIX_SMOOI_TO_OOP(shift));
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!y) return STIX_NULL;
|
||||||
|
|
||||||
|
sign = integer_to_oow (stix, y, &shift);
|
||||||
|
if (sign == 0) shift = STIX_SMOOI_MAX;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (shift == 0)
|
||||||
|
{
|
||||||
|
STIX_ASSERT (is_normalized_integer (stix, x));
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
STIX_ASSERT (sign >= 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (1);
|
||||||
|
|
||||||
|
/* this part must not be reached */
|
||||||
|
STIX_ASSERT (!"internal error - must not happen");
|
||||||
|
stix->errnum = STIX_EINTERN;
|
||||||
|
return STIX_NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
stix_oop_t stix_bitshiftint (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
stix_oop_t stix_bitshiftint (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
||||||
{
|
{
|
||||||
/* left shift if y is positive,
|
/* left shift if y is positive,
|
||||||
@ -2338,217 +2644,143 @@ stix_oop_t stix_bitshiftint (stix_t* stix, stix_oop_t x, stix_oop_t y)
|
|||||||
return make_bigint_with_ooi (stix, v);
|
return make_bigint_with_ooi (stix, v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (STIX_OOP_IS_SMOOI(x))
|
|
||||||
{
|
|
||||||
stix_ooi_t v;
|
|
||||||
|
|
||||||
if (!is_integer(stix,y)) goto oops_einval;
|
|
||||||
|
|
||||||
v = STIX_OOP_TO_SMOOI(x);
|
|
||||||
if (v == 0) return STIX_SMOOI_TO_OOP(0);
|
|
||||||
|
|
||||||
if (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer)
|
|
||||||
{
|
|
||||||
/* right shift - special case.
|
|
||||||
* x is a small integer. it is just a few bytes long.
|
|
||||||
* y is a large negative integer. its smallest absolute value
|
|
||||||
* is STIX_SMOOI_MAX. i know the final answer. */
|
|
||||||
return (v < 0)? STIX_SMOOI_TO_OOP(-1): STIX_SMOOI_TO_OOP(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
stix_pushtmp (stix, &y);
|
|
||||||
x = make_bigint_with_ooi (stix, v);
|
|
||||||
stix_poptmp (stix);
|
|
||||||
if (!x) return STIX_NULL;
|
|
||||||
|
|
||||||
goto bigint_and_bigint;
|
|
||||||
}
|
|
||||||
else if (STIX_OOP_IS_SMOOI(y))
|
|
||||||
{
|
|
||||||
stix_ooi_t v;
|
|
||||||
|
|
||||||
if (!is_integer(stix,x)) goto oops_einval;
|
|
||||||
|
|
||||||
v = STIX_OOP_TO_SMOOI(y);
|
|
||||||
if (v == 0) return clone_bigint (stix, x, STIX_OBJ_GET_SIZE(x));
|
|
||||||
|
|
||||||
stix_pushtmp (stix, &x);
|
|
||||||
y = make_bigint_with_ooi (stix, v);
|
|
||||||
stix_poptmp (stix);
|
|
||||||
if (!y) return STIX_NULL;
|
|
||||||
|
|
||||||
goto bigint_and_bigint;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
stix_oop_t z;
|
|
||||||
int sign, negx, negy;
|
int sign, negx, negy;
|
||||||
stix_oow_t shift;
|
stix_oow_t shift;
|
||||||
|
|
||||||
if (!is_integer(stix,x) || !is_integer(stix, y)) goto oops_einval;
|
if (STIX_OOP_IS_SMOOI(x))
|
||||||
|
|
||||||
bigint_and_bigint:
|
|
||||||
negx = (STIX_OBJ_GET_CLASS(x) == stix->_large_negative_integer)? 1: 0;
|
|
||||||
negy = (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer)? 1: 0;
|
|
||||||
|
|
||||||
sign = bigint_to_oow (stix, y, &shift);
|
|
||||||
if (sign == 0)
|
|
||||||
{
|
{
|
||||||
/* y is too big or too small */
|
stix_ooi_t v;
|
||||||
if (negy)
|
|
||||||
|
if (!is_integer(stix,y)) goto oops_einval;
|
||||||
|
|
||||||
|
v = STIX_OOP_TO_SMOOI(x);
|
||||||
|
if (v == 0) return STIX_SMOOI_TO_OOP(0);
|
||||||
|
|
||||||
|
if (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer)
|
||||||
{
|
{
|
||||||
/* right shift */
|
/* right shift - special case.
|
||||||
#if defined(STIX_LIMIT_OBJ_SIZE)
|
* x is a small integer. it is just a few bytes long.
|
||||||
/* the maximum number of bit shifts are guaranteed to be
|
* y is a large negative integer. its smallest absolute value
|
||||||
* small enough to fit into the stix_oow_t type. so i can
|
* is STIX_SMOOI_MAX. i know the final answer. */
|
||||||
* easily assume that all bits are shifted out */
|
return (v < 0)? STIX_SMOOI_TO_OOP(-1): STIX_SMOOI_TO_OOP(0);
|
||||||
STIX_ASSERT (STIX_TYPE_MAX(stix_oow_t) >= STIX_OBJ_SIZE_MAX * 8);
|
|
||||||
return (negx)? STIX_SMOOI_TO_OOP(-1): STIX_SMOOI_TO_OOP(0);
|
|
||||||
#else
|
|
||||||
/* TODO: */
|
|
||||||
/* TODO: */
|
|
||||||
/* TODO: */
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
stix_pushtmp (stix, &y);
|
||||||
|
x = make_bigint_with_ooi (stix, v);
|
||||||
|
stix_poptmp (stix);
|
||||||
|
if (!x) return STIX_NULL;
|
||||||
|
|
||||||
|
goto bigint_and_bigint;
|
||||||
|
}
|
||||||
|
else if (STIX_OOP_IS_SMOOI(y))
|
||||||
|
{
|
||||||
|
stix_ooi_t v;
|
||||||
|
|
||||||
|
if (!is_integer(stix,x)) goto oops_einval;
|
||||||
|
|
||||||
|
v = STIX_OOP_TO_SMOOI(y);
|
||||||
|
if (v == 0) return clone_bigint (stix, x, STIX_OBJ_GET_SIZE(x));
|
||||||
|
|
||||||
|
negx = (STIX_OBJ_GET_CLASS(x) == stix->_large_negative_integer)? 1: 0;
|
||||||
|
if (v > 0)
|
||||||
|
{
|
||||||
|
sign = 1;
|
||||||
|
negy = 0;
|
||||||
|
shift = v;
|
||||||
|
goto bigint_and_positive_oow;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sign = -1;
|
||||||
|
negy = 1;
|
||||||
|
shift = -v;
|
||||||
|
goto bigint_and_negative_oow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stix_oop_t z;
|
||||||
|
|
||||||
|
if (!is_integer(stix,x) || !is_integer(stix, y)) goto oops_einval;
|
||||||
|
|
||||||
|
bigint_and_bigint:
|
||||||
|
negx = (STIX_OBJ_GET_CLASS(x) == stix->_large_negative_integer)? 1: 0;
|
||||||
|
negy = (STIX_OBJ_GET_CLASS(y) == stix->_large_negative_integer)? 1: 0;
|
||||||
|
|
||||||
|
sign = integer_to_oow (stix, y, &shift);
|
||||||
|
if (sign == 0)
|
||||||
|
{
|
||||||
|
/* y is too big or too small */
|
||||||
|
if (negy)
|
||||||
|
{
|
||||||
|
/* right shift */
|
||||||
|
#if defined(STIX_LIMIT_OBJ_SIZE)
|
||||||
|
/* the maximum number of bit shifts are guaranteed to be
|
||||||
|
* small enough to fit into the stix_oow_t type. so i can
|
||||||
|
* easily assume that all bits are shifted out */
|
||||||
|
STIX_ASSERT (STIX_TYPE_MAX(stix_oow_t) >= STIX_OBJ_SIZE_MAX * 8);
|
||||||
|
return (negx)? STIX_SMOOI_TO_OOP(-1): STIX_SMOOI_TO_OOP(0);
|
||||||
|
#else
|
||||||
|
if (negx)
|
||||||
|
return rshift_negative_bigint_and_normalize (stix, x, y);
|
||||||
|
else
|
||||||
|
return rshift_positive_bigint_and_normalize (stix, x, y);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* left shift */
|
||||||
|
#if defined(STIX_LIMIT_OBJ_SIZE)
|
||||||
|
/* the maximum number of bit shifts are guaranteed to be
|
||||||
|
* small enough to fit into the stix_oow_t type. so i can
|
||||||
|
* simply return a failure here becuase it's surely too
|
||||||
|
* large after shifting */
|
||||||
|
STIX_ASSERT (STIX_TYPE_MAX(stix_oow_t) >= STIX_OBJ_SIZE_MAX * 8);
|
||||||
|
stix->errnum = STIX_EOOMEM; /* is it a soft failure or a hard failure? is this error code proper? */
|
||||||
|
return STIX_NULL;
|
||||||
|
#else
|
||||||
|
return lshift_bigint_and_normalize (stix, x, y);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (sign >= 1)
|
||||||
{
|
{
|
||||||
/* left shift */
|
/* left shift */
|
||||||
#if defined(STIX_LIMIT_OBJ_SIZE)
|
stix_oow_t wshift;
|
||||||
/* the maximum number of bit shifts are guaranteed to be
|
|
||||||
* small enough to fit into the stix_oow_t type. so i can
|
|
||||||
* simply return a failure here becuase it's surely too
|
|
||||||
* large after shifting */
|
|
||||||
STIX_ASSERT (STIX_TYPE_MAX(stix_oow_t) >= STIX_OBJ_SIZE_MAX * 8);
|
|
||||||
stix->errnum = STIX_EOOMEM; /* is it a soft failure or a hard failure? is this error code proper? */
|
|
||||||
return STIX_NULL;
|
|
||||||
#else
|
|
||||||
/* this loop is very inefficient as shifting is repeated
|
|
||||||
* with lshift_unsigned_array(). however, this part of the
|
|
||||||
* code is not likey to be useful because the amount of
|
|
||||||
* memory available is certainly not enough to support
|
|
||||||
* huge shifts greater than STIX_TYPE_MAX(stix_oow_t) */
|
|
||||||
do
|
|
||||||
{
|
|
||||||
/* for convenience only in subtraction below.
|
|
||||||
* should it be between STIX_SMOOI_MAX and STIX_TYPE_MAX(stix_oow_t),
|
|
||||||
* the second parameter to stix_subints() can't be composed
|
|
||||||
* using STIX_SMOOI_TO_OOP() */
|
|
||||||
shift = STIX_SMOOI_MAX;
|
|
||||||
wshift = shift / STIX_LIW_BITS;
|
|
||||||
if (shift > wshift * STIX_LIW_BITS) wshift++;
|
|
||||||
|
|
||||||
stix_pushtmp (stix, &y);
|
bigint_and_positive_oow:
|
||||||
z = expand_bigint (stix, x, wshift);
|
wshift = shift / STIX_LIW_BITS;
|
||||||
stix_poptmp (stix);
|
if (shift > wshift * STIX_LIW_BITS) wshift++;
|
||||||
|
|
||||||
|
z = expand_bigint (stix, x, wshift);
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
|
lshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* right shift */
|
||||||
|
bigint_and_negative_oow:
|
||||||
|
|
||||||
|
STIX_ASSERT (sign <= -1);
|
||||||
|
|
||||||
|
if (negx)
|
||||||
|
{
|
||||||
|
z = rshift_negative_bigint (stix, x, shift);
|
||||||
if (!z) return STIX_NULL;
|
if (!z) return STIX_NULL;
|
||||||
|
|
||||||
lshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
|
||||||
stix_pushtmp (stix, &y);
|
|
||||||
x = normalize_bigint (stix, z);
|
|
||||||
stix_poptmp (stix);
|
|
||||||
if (!x) return STIX_NULL;
|
|
||||||
|
|
||||||
stix_pushtmp (stix, &x);
|
|
||||||
y = stix_subints (stix, y, STIX_SMOOI_TO_OOP(shift));
|
|
||||||
stix_poptmp (stix);
|
|
||||||
if (!y) return STIX_NULL;
|
|
||||||
|
|
||||||
sign = bigint_to_oow (stix, y, &shift);
|
|
||||||
}
|
}
|
||||||
while (sign == 0);
|
|
||||||
|
|
||||||
STIX_ASSERT (sign >= 1);
|
|
||||||
|
|
||||||
if (shift)
|
|
||||||
goto left_shift_last;
|
|
||||||
else
|
else
|
||||||
z = x;
|
{
|
||||||
#endif
|
z = clone_bigint (stix, x, STIX_OBJ_GET_SIZE(x));
|
||||||
|
if (!z) return STIX_NULL;
|
||||||
|
rshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return normalize_bigint(stix, z);
|
||||||
}
|
}
|
||||||
else if (sign >= 1)
|
|
||||||
{
|
|
||||||
stix_oow_t wshift;
|
|
||||||
|
|
||||||
left_shift_last:
|
|
||||||
wshift = shift / STIX_LIW_BITS;
|
|
||||||
if (shift > wshift * STIX_LIW_BITS) wshift++;
|
|
||||||
|
|
||||||
z = expand_bigint (stix, x, wshift);
|
|
||||||
if (!z) return STIX_NULL;
|
|
||||||
|
|
||||||
lshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* right shift */
|
|
||||||
STIX_ASSERT (sign <= -1);
|
|
||||||
|
|
||||||
if (negx)
|
|
||||||
{
|
|
||||||
stix_lidw_t w;
|
|
||||||
stix_lidw_t carry;
|
|
||||||
stix_oow_t i, xs;
|
|
||||||
|
|
||||||
xs = STIX_OBJ_GET_SIZE(x);
|
|
||||||
|
|
||||||
stix_pushtmp (stix, &x);
|
|
||||||
stix_pushtmp (stix, &y);
|
|
||||||
/* +1 for the second inversion below */
|
|
||||||
z = stix_instantiate (stix, stix->_large_negative_integer, STIX_NULL, xs + 1);
|
|
||||||
stix_poptmps (stix, 2);
|
|
||||||
if (!z) return STIX_NULL;
|
|
||||||
|
|
||||||
/* the following lines roughly for 'z = stix_bitinv (stix, x)' */
|
|
||||||
carry = 1;
|
|
||||||
for (i = 0; i < xs; i++)
|
|
||||||
{
|
|
||||||
w = (stix_lidw_t)((stix_liw_t)~((stix_oop_liword_t)x)->slot[i]) + carry;
|
|
||||||
carry = w >> STIX_LIW_BITS;
|
|
||||||
((stix_oop_liword_t)z)->slot[i] = ~(stix_liw_t)w;
|
|
||||||
}
|
|
||||||
STIX_ASSERT (carry == 0);
|
|
||||||
|
|
||||||
/* shift to the right */
|
|
||||||
rshift_unsigned_array (((stix_oop_liword_t)z)->slot, xs, shift);
|
|
||||||
|
|
||||||
/* the following lines roughly for 'z = stix_bitinv (stix, z)' */
|
|
||||||
#if 0
|
|
||||||
for (i = 0; i < xs; i++)
|
|
||||||
{
|
|
||||||
((stix_oop_liword_t)z)->slot[i] = ~((stix_oop_liword_t)z)->slot[i];
|
|
||||||
}
|
|
||||||
((stix_oop_liword_t)z)->slot[xs] = ~(stix_liw_t)0;
|
|
||||||
|
|
||||||
carry = 1;
|
|
||||||
for (i = 0; i <= xs; i++)
|
|
||||||
{
|
|
||||||
w = (stix_lidw_t)((stix_liw_t)~((stix_oop_liword_t)z)->slot[i]) + carry;
|
|
||||||
carry = w >> STIX_LIW_BITS;
|
|
||||||
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)w;
|
|
||||||
}
|
|
||||||
STIX_ASSERT (carry == 0);
|
|
||||||
#else
|
|
||||||
carry = 1;
|
|
||||||
for (i = 0; i < xs; i++)
|
|
||||||
{
|
|
||||||
w = (stix_lidw_t)(((stix_oop_liword_t)z)->slot[i]) + carry;
|
|
||||||
carry = w >> STIX_LIW_BITS;
|
|
||||||
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)w;
|
|
||||||
}
|
|
||||||
((stix_oop_liword_t)z)->slot[i] = (stix_liw_t)carry;
|
|
||||||
STIX_ASSERT ((carry >> STIX_LIW_BITS) == 0);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
z = clone_bigint (stix, x, STIX_OBJ_GET_SIZE(x));
|
|
||||||
if (!z) return STIX_NULL;
|
|
||||||
rshift_unsigned_array (((stix_oop_liword_t)z)->slot, STIX_OBJ_GET_SIZE(z), shift);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return normalize_bigint(stix, z);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
oops_einval:
|
oops_einval:
|
||||||
@ -2848,28 +3080,8 @@ stix_oop_t stix_inttostr (stix_t* stix, stix_oop_t num, int radix)
|
|||||||
|
|
||||||
STIX_ASSERT (radix >= 2 && radix <= 36);
|
STIX_ASSERT (radix >= 2 && radix <= 36);
|
||||||
|
|
||||||
if (STIX_OOP_IS_SMOOI(num))
|
if (!is_integer(stix,num)) goto oops_einval;
|
||||||
{
|
v = integer_to_oow (stix, num, &w);
|
||||||
v = STIX_OOP_TO_SMOOI(num);
|
|
||||||
if (v < 0)
|
|
||||||
{
|
|
||||||
w = -v;
|
|
||||||
v = -1;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
w = v;
|
|
||||||
v = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!is_integer(stix,num))
|
|
||||||
{
|
|
||||||
goto oops_einval;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
v = bigint_to_oow (stix, num, &w);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (v)
|
if (v)
|
||||||
{
|
{
|
||||||
|
@ -57,7 +57,8 @@
|
|||||||
|
|
||||||
/* limit the maximum object size such that:
|
/* limit the maximum object size such that:
|
||||||
* 1. an index to an object field can be represented in a small integer.
|
* 1. an index to an object field can be represented in a small integer.
|
||||||
* 2. the maximum number of bit shifts can be represented in the stix_oow_t type.
|
* 2. the maximum number of bits including bit-shifts can be represented
|
||||||
|
* in the stix_oow_t type.
|
||||||
*/
|
*/
|
||||||
#define STIX_LIMIT_OBJ_SIZE
|
#define STIX_LIMIT_OBJ_SIZE
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user