Beispiel #1
0
void
mpd_copy(mpd_t *result, const mpd_t *a, mpd_context_t *ctx)
{
	uint32_t status = 0;
	if (!mpd_qcopy(result, a, &status)) {
		mpd_addstatus_raise(ctx, status);
	}
}
Beispiel #2
0
/* Round a number to prec digits. The adjusted exponent stays the same
   or increases by one if rounding up crosses a power of ten boundary.
   If result->digits would exceed MPD_MAX_PREC+1, MPD_Invalid_operation
   is set and the result is NaN. */
static inline void
_mpd_round(mpd_t *result, const mpd_t *a, mpd_ssize_t prec,
           const mpd_context_t *ctx, uint32_t *status)
{
    mpd_ssize_t exp = a->exp + a->digits - prec;

    if (prec <= 0) {
        mpd_seterror(result, MPD_Invalid_operation, status); /* GCOV_NOT_REACHED */
        return; /* GCOV_NOT_REACHED */
    }
    if (mpd_isspecial(a) || mpd_iszero(a)) {
        mpd_qcopy(result, a, status); /* GCOV_NOT_REACHED */
        return; /* GCOV_NOT_REACHED */
    }

    mpd_qrescale_fmt(result, a, exp, ctx, status);
    if (result->digits > prec) {
        mpd_qrescale_fmt(result, result, exp+1, ctx, status);
    }
}
Beispiel #3
0
/*
 * Return the string representation of an mpd_t, formatted according to 'spec'.
 * The format specification is assumed to be valid. Memory errors are indicated
 * as usual. This function is quiet.
 */
char *
mpd_qformat_spec(const mpd_t *dec, const mpd_spec_t *spec,
                 const mpd_context_t *ctx, uint32_t *status)
{
    mpd_uint_t dt[MPD_MINALLOC_MAX];
    mpd_t tmp = {MPD_STATIC|MPD_STATIC_DATA,0,0,0,MPD_MINALLOC_MAX,dt};
    mpd_ssize_t dplace = MPD_DEFAULT_DOTPLACE;
    mpd_mbstr_t result;
    mpd_spec_t stackspec;
    char type = spec->type;
    int flags = 0;


    if (spec->min_width > MPD_MAX_PREC) {
        *status |= MPD_Invalid_operation;
        return NULL;
    }

    if (isupper((uchar)type)) {
        type = tolower((uchar)type);
        flags |= MPD_FMT_UPPER;
    }
    if (spec->sign == ' ') {
        flags |= MPD_FMT_SIGN_SPACE;
    }
    else if (spec->sign == '+') {
        flags |= MPD_FMT_SIGN_PLUS;
    }

    if (mpd_isspecial(dec)) {
        if (spec->align == 'z') {
            stackspec = *spec;
            stackspec.fill[0] = ' ';
            stackspec.fill[1] = '\0';
            stackspec.align = '>';
            spec = &stackspec;
        }
    }
    else {
        uint32_t workstatus = 0;
        mpd_ssize_t prec;

        switch (type) {
        case 'g': flags |= MPD_FMT_TOSCI; break;
        case 'e': flags |= MPD_FMT_EXP; break;
        case '%': flags |= MPD_FMT_PERCENT;
                  if (!mpd_qcopy(&tmp, dec, status)) {
                      return NULL;
                  }
                  tmp.exp += 2;
                  dec = &tmp;
                  type = 'f'; /* fall through */
        case 'f': flags |= MPD_FMT_FIXED; break;
        default: abort(); /* debug: GCOV_NOT_REACHED */
        }

        if (spec->prec >= 0) {
            if (spec->prec > MPD_MAX_PREC) {
                *status |= MPD_Invalid_operation;
                goto error;
            }

            switch (type) {
            case 'g':
                prec = (spec->prec == 0) ? 1 : spec->prec;
                if (dec->digits > prec) {
                    _mpd_round(&tmp, dec, prec, ctx,
                               &workstatus);
                    dec = &tmp;
                }
                break;
            case 'e':
                if (mpd_iszero(dec)) {
                    dplace = 1-spec->prec;
                }
                else {
                    _mpd_round(&tmp, dec, spec->prec+1, ctx,
                               &workstatus);
                    dec = &tmp;
                }
                break;
            case 'f':
                mpd_qrescale(&tmp, dec, -spec->prec, ctx,
                             &workstatus);
                dec = &tmp;
                break;
            }
        }

        if (type == 'f') {
            if (mpd_iszero(dec) && dec->exp > 0) {
                mpd_qrescale(&tmp, dec, 0, ctx, &workstatus);
                dec = &tmp;
            }
        }

        if (workstatus&MPD_Errors) {
            *status |= (workstatus&MPD_Errors);
            goto error;
        }
    }

    /*
     * At this point, for all scaled or non-scaled decimals:
     *   1) 1 <= digits <= MAX_PREC+1
     *   2) adjexp(scaled) = adjexp(orig) [+1]
     *   3)   case 'g': MIN_ETINY <= exp <= MAX_EMAX+1
     *        case 'e': MIN_ETINY-MAX_PREC <= exp <= MAX_EMAX+1
     *        case 'f': MIN_ETINY <= exp <= MAX_EMAX+1
     *   4) max memory alloc in _mpd_to_string:
     *        case 'g': MAX_PREC+36
     *        case 'e': MAX_PREC+36
     *        case 'f': 2*MPD_MAX_PREC+30
     */
    result.nbytes = _mpd_to_string(&result.data, dec, flags, dplace);
    result.nchars = result.nbytes;
    if (result.nbytes < 0) {
        *status |= MPD_Malloc_error;
        goto error;
    }

    if (*spec->dot != '\0' && !mpd_isspecial(dec)) {
        if (result.nchars > MPD_MAX_PREC+36) {
            /* Since a group length of one is not explicitly
             * disallowed, ensure that it is always possible to
             * insert a four byte separator after each digit. */
            *status |= MPD_Invalid_operation;
            mpd_free(result.data);
            goto error;
        }
        if (!_mpd_apply_lconv(&result, spec, status)) {
            goto error;
        }
    }

    if (spec->min_width) {
        if (!_mpd_add_pad(&result, spec, status)) {
            goto error;
        }
    }

    mpd_del(&tmp);
    return result.data;

error:
    mpd_del(&tmp);
    return NULL;
}