Ejemplo n.º 1
0
static _Decimal128 mpd_to_dec128(mpd_t *in){
  uint64_t exp_part,significand[2];
  uint16_t *bases_data;
  ud128 ret;
  mpd_context_t ctx;
  size_t bases;
  uint32_t status = 0;

  mpd_ieee_context(&ctx,MPD_DECIMAL128);
  mpd_qfinalize(in, &ctx,&status);
  exp_part = in->exp + (uint64_t)mpd_trail_zeros(in) + 6176LL; /* rough guess? */
  in->exp = 0;
  bases = mpd_sizeinbase(in, UINT16_MAX+1);
  bases_data = __mingw_dfp_get_globals()->mpd_callocfunc(bases < 8 ? 8 : bases,sizeof(uint16_t));
  mpd_qexport_u16(bases_data,bases,UINT16_MAX+1,in,&status);
  significand[0] = bases_data[0] | (uint64_t)bases_data[1] << 16 | (uint64_t)bases_data[2] << 32 | (uint64_t)bases_data[3] << 48;
  significand[1] = bases_data[4] | (uint64_t)bases_data[5] << 16 | (uint64_t)bases_data[6] << 32 | (uint64_t)bases_data[7] << 48;
  __mingw_dfp_get_globals()->mpd_free(bases_data);
  ret.t0.sign = mpd_isnegative(in);
  if((significand[1] & (0x7ULL << 57)) == (0x1ULL << 49)) { /* 100 MSB? */
    ret.t2.bits = 0x3;
    ret.t2.mantissaL = significand[0];
    ret.t2.mantissaH = significand[1];
    ret.t2.exponent = exp_part;
  } else {
    ret.t1.mantissaL = significand[0];
    ret.t1.mantissaH = significand[1];
    ret.t1.exponent = exp_part;
  }
  return ret.d;

}
Ejemplo n.º 2
0
static _Decimal64 mpd_to_dec64(mpd_t *in){
  uint64_t exp_part, significand;
  uint32_t status = 0;
  size_t bases;
  uint16_t *bases_data;
  ud64 ret;
  mpd_context_t ctx;

  mpd_ieee_context(&ctx,MPD_DECIMAL64);
  mpd_qfinalize(in, &ctx,&status);

  exp_part = in->exp + (uint64_t)mpd_trail_zeros(in) + 398LL; /* rough guess? */
  in->exp = 0;
  bases = mpd_sizeinbase(in, UINT16_MAX+1);
  bases_data = __mingw_dfp_get_globals()->mpd_callocfunc(bases < 4 ? 4 : bases,sizeof(uint16_t));
  mpd_qexport_u16(bases_data,bases,UINT16_MAX+1,in,&status);
  significand = bases_data[0] | (uint64_t)bases_data[1] << 16 | (uint64_t)bases_data[2] << 32 | (uint64_t)bases_data[3] << 48;
  __mingw_dfp_get_globals()->mpd_free(bases_data);
  ret.t0.sign = mpd_isnegative(in);
  if((significand & (0x7ULL << 51)) == (0x1ULL << 53)) { /* 100 MSB? */
    ret.t2.bits = 0x3;
    ret.t2.mantissa = significand;
    ret.t2.exponent = exp_part;
  } else {
    ret.t1.mantissa = significand;
    ret.t1.exponent = exp_part;
  }
  return ret.d;
}
Ejemplo n.º 3
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);
}