fixed some problems in bigint multiplication

This commit is contained in:
hyunghwan.chung 2015-11-16 09:53:31 +00:00
parent 346131b3e3
commit 415921d4a7
2 changed files with 42 additions and 28 deletions

View File

@ -260,7 +260,7 @@ PROCESS TESTING
(1 + 2) dump. (1 + 2) dump.
##(-2305843009213693952 * 2305843009213693952) dump. ##(-2305843009213693952 * 2305843009213693952) dump.
(((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255) * ((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255)) dump. ## (((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255) * ((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255)) dump.
##((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255) dump. ##((-2305843009213693952 - 10) * (-2305843009213693952 - 10) *(-2305843009213693952 - 10) * (-2305843009213693952 - 10) * 255) dump.
##(-16rFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF * 1) dump. ##(-16rFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF * 1) dump.

View File

@ -68,24 +68,40 @@ static STIX_INLINE int oow_mul_overflow (stix_oow_t a, stix_oow_t b, stix_oow_t*
#endif #endif
#if (STIX_SIZEOF_OOI_T == STIX_SIZEOF_INT) && defined(STIX_HAVE_BUILTIN_SMUL_OVERFLOW) #if (STIX_SIZEOF_OOI_T == STIX_SIZEOF_INT) && defined(STIX_HAVE_BUILTIN_SMUL_OVERFLOW)
# define ooi_mul_overflow(a,b,c) __builtin_smul_overflow(a,b,c) # define smooi_mul_overflow(a,b,c) __builtin_smul_overflow(a,b,c)
#elif (STIX_SIZEOF_OOI_T == STIX_SIZEOF_LONG) && defined(STIX_HAVE_BUILTIN_SMULL_OVERFLOW) #elif (STIX_SIZEOF_OOI_T == STIX_SIZEOF_LONG) && defined(STIX_HAVE_BUILTIN_SMULL_OVERFLOW)
# define ooi_mul_overflow(a,b,c) __builtin_smull_overflow(a,b,c) # define smooi_mul_overflow(a,b,c) __builtin_smull_overflow(a,b,c)
#elif (STIX_SIZEOF_OOI_T == STIX_SIZEOF_LONG_LONG) && defined(STIX_HAVE_BUILTIN_SMULLL_OVERFLOW) #elif (STIX_SIZEOF_OOI_T == STIX_SIZEOF_LONG_LONG) && defined(STIX_HAVE_BUILTIN_SMULLL_OVERFLOW)
# define ooi_mul_overflow(a,b,c) __builtin_smulll_overflow(a,b,c) # define smooi_mul_overflow(a,b,c) __builtin_smulll_overflow(a,b,c)
#else #else
static STIX_INLINE int ooi_mul_overflow (stix_ooi_t a, stix_ooi_t b, stix_ooi_t* c) static STIX_INLINE int smooi_mul_overflow (stix_ooi_t a, stix_ooi_t b, stix_ooi_t* c)
{ {
#if (STIX_SIZEOF_UINTMAX_T > STIX_SIZEOF_OOI_T) #if (STIX_SIZEOF_UINTMAX_T > STIX_SIZEOF_OOI_T)
stix_intmax_t k; stix_intmax_t k;
STIX_ASSERT (STIX_IN_SMOOI_RANGE(a));
STIX_ASSERT (STIX_IN_SMOOI_RANGE(b));
k = (stix_intmax_t)a * (stix_intmax_t)b; k = (stix_intmax_t)a * (stix_intmax_t)b;
*c = (stix_ooi_t)k; *c = (stix_ooi_t)k;
return k > STIX_TYPE_MAX(stix_ooi_t) || k < STIX_TYPE_MIN(stix_ooi_t); return k > STIX_TYPE_MAX(stix_ooi_t) || k < STIX_TYPE_MIN(stix_ooi_t);
#else #else
/* TODO: fix this */
#error not implemented stix_ooi_t ua, ub;
STIX_ASSERT (STIX_IN_SMOOI_RANGE(a));
STIX_ASSERT (STIX_IN_SMOOI_RANGE(b));
*c = a * b; *c = a * b;
return b > 0 && a > STIX_TYPE_MAX(stix_ooi_t) / b; /* works for unsigned types only */
ub = (b >= 0)? b: -b;
ua = (a >= 0)? a: -a;
/* though this fomula basically works for unsigned types in principle,
* the values used here are all absolute values and they fall in
* a safe range to apply this fomula */
return ub > 0 && ua > STIX_TYPE_MAX(stix_ooi_t) / ub;
#endif #endif
} }
#endif #endif
@ -143,6 +159,7 @@ static STIX_INLINE stix_oop_t make_bigint_with_ooi (stix_t* stix, stix_ooi_t i)
#if defined(USE_FULL_WORD) #if defined(USE_FULL_WORD)
stix_oow_t w; stix_oow_t w;
STIX_ASSERT (STIX_ZIEOF(stix_oow_t) == STIX_SIZEOF(atom_t));
if (i >= 0) if (i >= 0)
{ {
w = i; w = i;
@ -150,7 +167,7 @@ static STIX_INLINE stix_oop_t make_bigint_with_ooi (stix_t* stix, stix_ooi_t i)
} }
else else
{ {
/* The caller must ensure that i is grater than the smallest value /* The caller must ensure that i is greater than the smallest value
* that stix_ooi_t can represent. otherwise, the absolute value * that stix_ooi_t can represent. otherwise, the absolute value
* cannot be held in stix_ooi_t. */ * cannot be held in stix_ooi_t. */
STIX_ASSERT (i > STIX_TYPE_MIN(stix_ooi_t)); STIX_ASSERT (i > STIX_TYPE_MIN(stix_ooi_t));
@ -779,8 +796,7 @@ stix_oop_t stix_mulints (stix_t* stix, stix_oop_t x, stix_oop_t y)
if (STIX_OOP_IS_SMOOI(x) && STIX_OOP_IS_SMOOI(y)) if (STIX_OOP_IS_SMOOI(x) && STIX_OOP_IS_SMOOI(y))
{ {
/*#if STIX_SIZEOF_INTMAX_T > STIX_SIZEOF_OOI_T*/ /* TOOD: uncomment this line and remove the next line after #else block has been tested */ #if STIX_SIZEOF_INTMAX_T > STIX_SIZEOF_OOI_T
#if STIX_SIZEOF_INTMAX_T <= STIX_SIZEOF_OOI_T
stix_intmax_t i; stix_intmax_t i;
i = (stix_intmax_t)STIX_OOP_TO_SMOOI(x) * (stix_intmax_t)STIX_OOP_TO_SMOOI(y); i = (stix_intmax_t)STIX_OOP_TO_SMOOI(x) * (stix_intmax_t)STIX_OOP_TO_SMOOI(y);
if (STIX_IN_SMOOI_RANGE(i)) return STIX_SMOOI_TO_OOP((stix_ooi_t)i); if (STIX_IN_SMOOI_RANGE(i)) return STIX_SMOOI_TO_OOP((stix_ooi_t)i);
@ -791,30 +807,27 @@ stix_oop_t stix_mulints (stix_t* stix, stix_oop_t x, stix_oop_t y)
xv = STIX_OOP_TO_SMOOI(x); xv = STIX_OOP_TO_SMOOI(x);
yv = STIX_OOP_TO_SMOOI(y); yv = STIX_OOP_TO_SMOOI(y);
if (ooi_mul_overflow (xv, yv, &i)) if (smooi_mul_overflow (xv, yv, &i))
{ {
/* overflowed /* overflowed - convert x and y normal objects and carry on */
* -----------------------------------------------------
* no need to call stix_pushtmp() on x and y as they are /* no need to call stix_pushtmp before creating x because
* known to be small integers and we don't need them. * xv and yv contains actual values needed */
* actual values are all in xv and yv. */ x = make_bigint_with_ooi (stix, xv);
if (!(x = make_bigint_with_ooi (stix, xv)) || if (!x) return STIX_NULL;
!(y = make_bigint_with_ooi (stix, yv))) return STIX_NULL;
stix_pushtmp (stix, &x); /* protect x made above */
y = make_bigint_with_ooi (stix, yv);
stix_poptmp (stix);
if (!y) return STIX_NULL;
goto normal;
} }
else else
{ {
if (STIX_IN_SMOOI_RANGE(i)) return STIX_SMOOI_TO_OOP(i); if (STIX_IN_SMOOI_RANGE(i)) return STIX_SMOOI_TO_OOP(i);
return make_bigint_with_ooi (stix, i); return make_bigint_with_ooi (stix, i);
} }
/*
stix_ooi_t i;
i = STIX_OOP_TO_SMOOI(x) * STIX_OOP_TO_SMOOI(y);
if (STIX_IN_SMOOI_RANGE(i)) return STIX_SMOOI_TO_OOP(i);
return make_bigint_with_ooi (stix, i);
*/
#endif #endif
} }
else else
@ -869,6 +882,7 @@ stix_oop_t stix_mulints (stix_t* stix, stix_oop_t x, stix_oop_t y)
if (!is_integer(stix,y)) goto oops_einval; if (!is_integer(stix,y)) goto oops_einval;
} }
normal:
z = multiply_unsigned_integers (stix, x, y); z = multiply_unsigned_integers (stix, x, y);
if (!z) return STIX_NULL; if (!z) return STIX_NULL;
if (STIX_OBJ_GET_CLASS(x) != STIX_OBJ_GET_CLASS(y)) if (STIX_OBJ_GET_CLASS(x) != STIX_OBJ_GET_CLASS(y))