Beispiel #1
0
/* The faster in-place functions are tested against std_trans(). */
static int
testit_uchar(void (* func)(uint8_t *, mpd_size_t, mpd_size_t), mpd_size_t rows, mpd_size_t cols)
{
	uint8_t *a = NULL, *src = NULL, *dest = NULL;
	clock_t start_fast, end_fast, start_std, end_std;
	mpd_size_t msize;
	mpd_size_t i;
	int ret = 1;

	msize = mul_size_t(rows, cols);
	if ((a = mpd_alloc(msize, sizeof *a)) == NULL) {
		goto error;
	}
	if ((src = mpd_alloc(msize, sizeof *src)) == NULL) {
		goto error;
	}
	if ((dest = mpd_alloc(msize, sizeof *dest)) == NULL) {
		goto error;
	}

	for (i = 0; i < msize; i++) {
		a[i] = src[i] = random();
	}

	start_std= clock();
	std_trans_c(dest, src, rows, cols);
	end_std= clock();

	start_fast = clock();
	func(a, rows, cols);
	end_fast = clock();

	for (i = 0; i < msize; i++) {
		if (a[i] != dest[i]) {
			fprintf(stderr, "FAIL: a[%"PRI_mpd_size_t"] = %d\t"
                                        "dest[%"PRI_mpd_size_t"] = %d\n",
			        i, a[i], i, dest[i]);
			exit(1);
		}
	}

	fprintf(stderr, "size: %10"PRI_mpd_size_t"\tstd_trans: %6.2f sec\t "
                        "in_place_trans: %6.2f sec\n",
		msize,
		(double)(end_std-start_std)/(double)CLOCKS_PER_SEC,
		(double)(end_fast-start_fast)/(double)CLOCKS_PER_SEC);


out:
	if (a) __mingw_dfp_get_globals()->mpd_free(a);
	if (src) __mingw_dfp_get_globals()->mpd_free(src);
	if (dest) __mingw_dfp_get_globals()->mpd_free(dest);
	return ret;

error:
	ret = 0;
	goto out;
}
Beispiel #2
0
/*
 * Convert a numeric-string to its locale-specific appearance.
 * The string must have one of these forms:
 *
 *     1) [sign] digits [exponent-part]
 *     2) [sign] digits '.' [digits] [exponent-part]
 *
 * Not allowed, since _mpd_to_string() never returns this form:
 *
 *     3) [sign] '.' digits [exponent-part]
 * 
 * Input: result->data := original numeric string (ASCII)
 *        result->bytes := strlen(result->data)
 *        result->nchars := strlen(result->data)
 *
 * Output: result->data := modified or original string
 *         result->bytes := strlen(result->data)
 *         result->nchars := number of characters (possibly UTF-8)
 */
static int
_mpd_apply_lconv(mpd_mbstr_t *result, const mpd_spec_t *spec, uint32_t *status)
{
    const char *sign = NULL, *intpart = NULL, *dot = NULL;
    const char *rest, *dp;
    char *decstring;
    mpd_ssize_t n_int, n_rest;

    /* original numeric string */
    dp = result->data;

    /* sign */
    if (*dp == '+' || *dp == '-' || *dp == ' ') {
        sign = dp++;
    }
    /* integer part */
    assert(isdigit((uchar)*dp));
    intpart = dp++;
    while (isdigit((uchar)*dp)) {
        dp++;
    }
    n_int = (mpd_ssize_t)(dp-intpart);
    /* decimal point */
    if (*dp == '.') {
        dp++; dot = spec->dot;
    }
    /* rest */
    rest = dp;
    n_rest = result->nbytes - (mpd_ssize_t)(dp-result->data);

    if (dot == NULL && (*spec->sep == '\0' || *spec->grouping == '\0')) {
        /* _mpd_add_sep_dot() would not change anything */
        return 1;
    }

    /* Determine the size of the new decimal string after inserting the
     * decimal point, optional separators and optional padding. */
    decstring = result->data;
    result->data = NULL;
    _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
                     rest, n_rest, spec);

    result->data = mpd_alloc(result->nbytes+1, 1);
    if (result->data == NULL) {
        *status |= MPD_Malloc_error;
        mpd_free(decstring);
        return 0;
    }

    /* Perform actual writes. */
    _mpd_add_sep_dot(result, sign, intpart, n_int, dot,
                     rest, n_rest, spec);

    mpd_free(decstring);
    return 1;
}
Beispiel #3
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;
}
Beispiel #4
0
/*
 * Set *result to the string representation of a decimal. Return the length
 * of *result, not including the terminating '\0' character.
 *
 * Formatting is done according to 'flags'. A return value of -1 with *result
 * set to NULL indicates MPD_Malloc_error.
 *
 * 'dplace' is the default place of the decimal point. It is always set to
 * MPD_DEFAULT_DOTPLACE except for zeros in combination with MPD_FMT_EXP.
 */
static mpd_ssize_t
_mpd_to_string(char **result, const mpd_t *dec, int flags, mpd_ssize_t dplace)
{
    char *decstring = NULL, *cp = NULL;
    mpd_ssize_t ldigits;
    mpd_ssize_t mem = 0, k;

    if (mpd_isspecial(dec)) {

        mem = sizeof "-Infinity";
        if (mpd_isnan(dec) && dec->len > 0) {
            /* diagnostic code */
            mem += dec->digits;
        }
        cp = decstring = mpd_alloc(mem, sizeof *decstring);
        if (cp == NULL) {
            *result = NULL;
            return -1;
        }

        if (mpd_isnegative(dec)) {
            *cp++ = '-';
        }
        else if (flags&MPD_FMT_SIGN_SPACE) {
            *cp++ = ' ';
        }
        else if (flags&MPD_FMT_SIGN_PLUS) {
            *cp++ = '+';
        }

        if (mpd_isnan(dec)) {
            if (mpd_isqnan(dec)) {
                strcpy(cp, "NaN");
                cp += 3;
            }
            else {
                strcpy(cp, "sNaN");
                cp += 4;
            }
            if (dec->len > 0) { /* diagnostic code */
                cp = coeff_to_string(cp, dec);
            }
        }
        else if (mpd_isinfinite(dec)) {
            strcpy(cp, "Infinity");
            cp += 8;
        }
        else { /* debug */
            abort(); /* GCOV_NOT_REACHED */
        }
    }
    else {
        assert(dec->len > 0);

        /*
         * For easier manipulation of the decimal point's location
         * and the exponent that is finally printed, the number is
         * rescaled to a virtual representation with exp = 0. Here
         * ldigits denotes the number of decimal digits to the left
         * of the decimal point and remains constant once initialized.
         *
         * dplace is the location of the decimal point relative to
         * the start of the coefficient. Note that 3) always holds
         * when dplace is shifted.
         *
         *   1) ldigits := dec->digits - dec->exp
         *   2) dplace  := ldigits            (initially)
         *   3) exp     := ldigits - dplace   (initially exp = 0)
         *
         *   0.00000_.____._____000000.
         *    ^      ^    ^           ^
         *    |      |    |           |
         *    |      |    |           `- dplace >= digits
         *    |      |    `- dplace in the middle of the coefficient
         *    |      ` dplace = 1 (after the first coefficient digit)
         *    `- dplace <= 0
         */

        ldigits = dec->digits + dec->exp;

        if (flags&MPD_FMT_EXP) {
            ;
        }
        else if (flags&MPD_FMT_FIXED || (dec->exp <= 0 && ldigits > -6)) {
            /* MPD_FMT_FIXED: always use fixed point notation.
             * MPD_FMT_TOSCI, MPD_FMT_TOENG: for a certain range,
             * override exponent notation. */
            dplace = ldigits;
        }
        else if (flags&MPD_FMT_TOENG) {
            if (mpd_iszero(dec)) {
                /* If the exponent is divisible by three,
                 * dplace = 1. Otherwise, move dplace one
                 * or two places to the left. */
                dplace = -1 + mod_mpd_ssize_t(dec->exp+2, 3);
            }
            else { /* ldigits-1 is the adjusted exponent, which
                * should be divisible by three. If not, move
                * dplace one or two places to the right. */
                dplace += mod_mpd_ssize_t(ldigits-1, 3);
            }
        }

        /*
         * Basic space requirements:
         *
         * [-][.][coeffdigits][E][-][expdigits+1][%]['\0']
         *
         * If the decimal point lies outside of the coefficient digits,
         * space is adjusted accordingly.
         */
        if (dplace <= 0) {
            mem = -dplace + dec->digits + 2;
        }
        else if (dplace >= dec->digits) {
            mem = dplace;
        }
        else {
            mem = dec->digits;
        }
        mem += (MPD_EXPDIGITS+1+6);

        cp = decstring = mpd_alloc(mem, sizeof *decstring);
        if (cp == NULL) {
            *result = NULL;
            return -1;
        }


        if (mpd_isnegative(dec)) {
            *cp++ = '-';
        }
        else if (flags&MPD_FMT_SIGN_SPACE) {
            *cp++ = ' ';
        }
        else if (flags&MPD_FMT_SIGN_PLUS) {
            *cp++ = '+';
        }

        if (dplace <= 0) {
            /* space: -dplace+dec->digits+2 */
            *cp++ = '0';
            *cp++ = '.';
            for (k = 0; k < -dplace; k++) {
                *cp++ = '0';
            }
            cp = coeff_to_string(cp, dec);
        }
        else if (dplace >= dec->digits) {
            /* space: dplace */
            cp = coeff_to_string(cp, dec);
            for (k = 0; k < dplace-dec->digits; k++) {
                *cp++ = '0';
            }
        }
        else {
            /* space: dec->digits+1 */
            cp = coeff_to_string_dot(cp, cp+dplace, dec);
        }

        /*
         * Conditions for printing an exponent:
         *
         *   MPD_FMT_TOSCI, MPD_FMT_TOENG: only if ldigits != dplace
         *   MPD_FMT_FIXED:                never (ldigits == dplace)
         *   MPD_FMT_EXP:                  always
         */
        if (ldigits != dplace || flags&MPD_FMT_EXP) {
            /* space: expdigits+2 */
            *cp++ = (flags&MPD_FMT_UPPER) ? 'E' : 'e';
            cp = exp_to_string(cp, ldigits-dplace);
        }

        if (flags&MPD_FMT_PERCENT) {
            *cp++ = '%';
        }
    }

    assert(cp < decstring+mem);
    assert(cp-decstring < MPD_SSIZE_MAX);

    *cp = '\0';
    *result = decstring;
    return (mpd_ssize_t)(cp-decstring);
}