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; }
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; }
/* * 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); }