Пример #1
0
/*
 * Knuth, TAOCP, Volume 2, 4.3.1:
 *     w := product of u (len m) and v (len n)
 *     w must be initialized to zero
 */
void
_mpd_basemul(mpd_uint_t *w, const mpd_uint_t *u, const mpd_uint_t *v,
             mpd_size_t m, mpd_size_t n)
{
    mpd_uint_t hi, lo;
    mpd_uint_t carry;
    mpd_size_t i, j;

    assert(m > 0 && n > 0);

    for (j=0; j < n; j++) {
        carry = 0;
        for (i=0; i < m; i++) {

            _mpd_mul_words(&hi, &lo, u[i], v[j]);
            lo = w[i+j] + lo;
            if (lo < w[i+j]) hi++;
            lo = carry + lo;
            if (lo < carry) hi++;

            _mpd_div_words_r(&carry, &w[i+j], hi, lo);
        }
        w[j+m] = carry;
    }
}
Пример #2
0
/* w := product of u (len n) and v (single word) */
void
_mpd_shortmul(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)
{
    mpd_uint_t hi, lo;
    mpd_uint_t carry = 0;
    mpd_size_t i;

    assert(n > 0);

    for (i=0; i < n; i++) {

        _mpd_mul_words(&hi, &lo, u[i], v);
        lo = carry + lo;
        if (lo < carry) hi++;

        _mpd_div_words_r(&carry, &w[i], hi, lo);
    }
    w[i] = carry;
}
Пример #3
0
/*
 * Knuth, TAOCP Volume 2, 4.3.1, exercise 16:
 *     w := quotient of u (len n) divided by a single word v
 */
mpd_uint_t
_mpd_shortdiv(mpd_uint_t *w, const mpd_uint_t *u, mpd_size_t n, mpd_uint_t v)
{
    mpd_uint_t hi, lo;
    mpd_uint_t rem = 0;
    mpd_size_t i;

    assert(n > 0);

    for (i=n-1; i != MPD_SIZE_MAX; i--) {

        _mpd_mul_words(&hi, &lo, rem, MPD_RADIX);
        lo = u[i] + lo;
        if (lo < u[i]) hi++;

        _mpd_div_words(&w[i], &rem, hi, lo, v);
    }

    return rem;
}
Пример #4
0
/*
 * Knuth, TAOCP Volume 2, 4.3.1:
 *     q, r := quotient and remainder of uconst (len nplusm)
 *             divided by vconst (len n)
 *     nplusm >= n
 *
 * If r is not NULL, r will contain the remainder. If r is NULL, the
 * return value indicates if there is a remainder: 1 for true, 0 for
 * false.  A return value of -1 indicates an error.
 */
int
_mpd_basedivmod(mpd_uint_t *q, mpd_uint_t *r,
                const mpd_uint_t *uconst, const mpd_uint_t *vconst,
                mpd_size_t nplusm, mpd_size_t n)
{
    mpd_uint_t ustatic[MPD_MINALLOC_MAX];
    mpd_uint_t vstatic[MPD_MINALLOC_MAX];
    mpd_uint_t *u = ustatic;
    mpd_uint_t *v = vstatic;
    mpd_uint_t d, qhat, rhat, w2[2];
    mpd_uint_t hi, lo, x;
    mpd_uint_t carry;
    mpd_size_t i, j, m;
    int retval = 0;

    assert(n > 1 && nplusm >= n);
    m = sub_size_t(nplusm, n);

    /* D1: normalize */
    d = MPD_RADIX / (vconst[n-1] + 1);

    if (nplusm >= MPD_MINALLOC_MAX) {
        if ((u = mpd_alloc(nplusm+1, sizeof *u)) == NULL) {
            return -1;
        }
    }
    if (n >= MPD_MINALLOC_MAX) {
        if ((v = mpd_alloc(n+1, sizeof *v)) == NULL) {
            mpd_free(u);
            return -1;
        }
    }

    _mpd_shortmul(u, uconst, nplusm, d);
    _mpd_shortmul(v, vconst, n, d);

    /* D2: loop */
    for (j=m; j != MPD_SIZE_MAX; j--) {

        /* D3: calculate qhat and rhat */
        rhat = _mpd_shortdiv(w2, u+j+n-1, 2, v[n-1]);
        qhat = w2[1] * MPD_RADIX + w2[0];

        while (1) {
            if (qhat < MPD_RADIX) {
                _mpd_singlemul(w2, qhat, v[n-2]);
                if (w2[1] <= rhat) {
                    if (w2[1] != rhat || w2[0] <= u[j+n-2]) {
                        break;
                    }
                }
            }
            qhat -= 1;
            rhat += v[n-1];
            if (rhat < v[n-1] || rhat >= MPD_RADIX) {
                break;
            }
        }
        /* D4: multiply and subtract */
        carry = 0;
        for (i=0; i <= n; i++) {

            _mpd_mul_words(&hi, &lo, qhat, v[i]);

            lo = carry + lo;
            if (lo < carry) hi++;

            _mpd_div_words_r(&hi, &lo, hi, lo);

            x = u[i+j] - lo;
            carry = (u[i+j] < x);
            u[i+j] = carry ? x+MPD_RADIX : x;
            carry += hi;
        }
        q[j] = qhat;
        /* D5: test remainder */
        if (carry) {
            q[j] -= 1;
            /* D6: add back */
            (void)_mpd_baseadd(u+j, u+j, v, n+1, n);
        }
    }

    /* D8: unnormalize */
    if (r != NULL) {
        _mpd_shortdiv(r, u, n, d);
        /* we are not interested in the return value here */
        retval = 0;
    }
    else {
        retval = !_mpd_isallzero(u, n);
    }


if (u != ustatic) mpd_free(u);
if (v != vstatic) mpd_free(v);
return retval;
}