static void decimal_to_decnumber (const REAL_VALUE_TYPE *r, decNumber *dn) { decContext set; decContextDefault (&set, DEC_INIT_DECIMAL128); set.traps = 0; switch (r->cl) { case rvc_zero: decNumberZero (dn); break; case rvc_inf: decNumberFromString (dn, (char *)"Infinity", &set); break; case rvc_nan: if (r->signalling) decNumberFromString (dn, (char *)"snan", &set); else decNumberFromString (dn, (char *)"nan", &set); break; case rvc_normal: gcc_assert (r->decimal); decimal128ToNumber ((decimal128 *) r->sig, dn); break; default: gcc_unreachable (); } /* Fix up sign bit. */ if (r->sign != decNumberIsNegative (dn)) dn->bits ^= DECNEG; }
int main(int argc, char *argv[]) { { // excerpt for User's Guide starts here--------------------------| decNumber one, mtwo, hundred; // constants decNumber start, rate, years; // parameters decNumber total; // result decContext set; // working context uint8_t startpack[]={0x01, 0x00, 0x00, 0x0C}; // investment=100000 int32_t startscale=0; uint8_t ratepack[]={0x06, 0x5C}; // rate=6.5% int32_t ratescale=1; uint8_t yearspack[]={0x02, 0x0C}; // years=20 int32_t yearsscale=0; uint8_t respack[16]; // result, packed int32_t resscale; // .. char hexes[49]; // for packed->hex int i; // counter if (argc<0) printf("%s", argv[1]); // noop for warning decContextDefault(&set, DEC_INIT_BASE); // initialize set.traps=0; // no traps set.digits=25; // precision 25 decNumberFromString(&one, "1", &set); // set constants decNumberFromString(&mtwo, "-2", &set); decNumberFromString(&hundred, "100", &set); decPackedToNumber(startpack, sizeof(startpack), &startscale, &start); decPackedToNumber(ratepack, sizeof(ratepack), &ratescale, &rate); decPackedToNumber(yearspack, sizeof(yearspack), &yearsscale, &years); decNumberDivide(&rate, &rate, &hundred, &set); // rate=rate/100 decNumberAdd(&rate, &rate, &one, &set); // rate=rate+1 decNumberPower(&rate, &rate, &years, &set); // rate=rate^years decNumberMultiply(&total, &rate, &start, &set); // total=rate*start decNumberRescale(&total, &total, &mtwo, &set); // two digits please decPackedFromNumber(respack, sizeof(respack), &resscale, &total); // lay out the total as sixteen hexadecimal pairs for (i=0; i<16; i++) { sprintf(&hexes[i*3], "%02x ", respack[i]); } printf("Result: %s (scale=%ld)\n", hexes, (long int)resscale); } //---------------------------------------------------------------| return 0; } // main
DecimalDecNumber &DecimalDecNumber::operator=(double rhs) { char buffer[512] = {0}; // Stack allocated string snprintf(buffer, 511, "%0.15lg", rhs); decNumberFromString(&m_value, buffer, &m_context); return *this; }
static void decimal_to_decnumber (const REAL_VALUE_TYPE *r, decNumber *dn) { decContext set; decContextDefault (&set, DEC_INIT_DECIMAL128); set.traps = 0; switch (r->cl) { case rvc_zero: decNumberZero (dn); break; case rvc_inf: decNumberFromString (dn, "Infinity", &set); break; case rvc_nan: if (r->signalling) decNumberFromString (dn, "snan", &set); else decNumberFromString (dn, "nan", &set); break; case rvc_normal: if (!r->decimal) { /* dconst{1,2,m1,half} are used in various places in the middle-end and optimizers, allow them here as an exception by converting them to decimal. */ if (memcmp (r, &dconst1, sizeof (*r)) == 0) { decNumberFromString (dn, "1", &set); break; } if (memcmp (r, &dconst2, sizeof (*r)) == 0) { decNumberFromString (dn, "2", &set); break; } if (memcmp (r, &dconstm1, sizeof (*r)) == 0) { decNumberFromString (dn, "-1", &set); break; } if (memcmp (r, &dconsthalf, sizeof (*r)) == 0) { decNumberFromString (dn, "0.5", &set); break; } gcc_unreachable (); } decimal128ToNumber ((const decimal128 *) r->sig, dn); break; default: gcc_unreachable (); } /* Fix up sign bit. */ if (r->sign != decNumberIsNegative (dn)) dn->bits ^= DECNEG; }
INT_TYPE DFP_TO_INT (DFP_C_TYPE x) { /* decNumber's decimal* types have the same format as C's _Decimal* types, but they have different calling conventions. */ IEEE_TYPE s; char buf[BUFMAX]; char *pos; decNumber qval, n1, n2; decContext context; decContextDefault (&context, CONTEXT_INIT); /* Need non-default rounding mode here. */ context.round = DEC_ROUND_DOWN; HOST_TO_IEEE (x, &s); TO_INTERNAL (&s, &n1); /* Rescale if the exponent is less than zero. */ decNumberToIntegralValue (&n2, &n1, &context); /* Get a value to use for the quantize call. */ decNumberFromString (&qval, (char *) "1.0", &context); /* Force the exponent to zero. */ decNumberQuantize (&n1, &n2, &qval, &context); /* This is based on text in N1107 section 5.1; it might turn out to be undefined behavior instead. */ if (context.status & DEC_Invalid_operation) { #if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) if (decNumberIsNegative(&n2)) return INT_MIN; else return INT_MAX; #elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) if (decNumberIsNegative(&n2)) /* Find a defined constant that will work here. */ return (-9223372036854775807LL - 1LL); else /* Find a defined constant that will work here. */ return 9223372036854775807LL; #elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) return UINT_MAX; #elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) /* Find a defined constant that will work here. */ return 18446744073709551615ULL; #endif } /* Get a string, which at this point will not include an exponent. */ decNumberToString (&n1, buf); /* Ignore the fractional part. */ pos = strchr (buf, '.'); if (pos) *pos = 0; /* Use a C library function to convert to the integral type. */ return STR_TO_INT (buf, NULL, 10); }
DecimalDecNumber::DecimalDecNumber(double rhs) { decContextDefault(&m_context, DEC_INIT_BASE); // initialize m_context.traps = 0; // no traps, thank you m_context.digits = DECNUMDIGITS; // set precision char buffer[512] = {0}; // Stack allocated string snprintf(buffer, 511, "%0.15lg", rhs); decNumberFromString(&m_value, buffer, &m_context); }
void decimal_real_from_string (REAL_VALUE_TYPE *r, const char *s) { decNumber dn; decContext set; decContextDefault (&set, DEC_INIT_DECIMAL128); set.traps = 0; decNumberFromString (&dn, (char *) s, &set); /* It would be more efficient to store directly in decNumber format, but that is impractical from current data structure size. Encoding as a decimal128 is much more compact. */ decimal_from_decnumber (r, &dn, &set); }
/* ------------------------------------------------------------------ */ decimal64 * decimal64FromString (decimal64 * result, const char *string, decContext * set) { decContext dc; decNumber dn; decContextDefault (&dc, DEC_INIT_DECIMAL64); dc.round = set->round; decNumberFromString (&dn, string, &dc); decimal64FromNumber (result, &dn, &dc); if (dc.status != 0) decContextSetStatus (set, dc.status); return result; }
int main(int argc, char *argv[]) { decNumber a, b; // working numbers decContext set; // working context char string[DECNUMDIGITS+14]; // conversion buffer decContextTestEndian(0); // warn if DECLITEND is wrong if (argc<3) { // not enough words printf("Please supply two numbers to add.\n"); return 1; } decContextDefault(&set, DEC_INIT_BASE); // initialize set.traps=0; // no traps, thank you set.digits=DECNUMDIGITS; // set precision decNumberFromString(&a, argv[1], &set); decNumberFromString(&b, argv[2], &set); decNumberAdd(&a, &a, &b, &set); // a=a+b decNumberToString(&a, string); printf("%s + %s => %s\n", argv[1], argv[2], string); return 0; } // main
DecimalDecNumber::DecimalDecNumber(uint64 rhs) { decContextDefault(&m_context, DEC_INIT_BASE); // initialize m_context.traps = 0; // no traps, thank you m_context.digits = DECNUMDIGITS; // set precision if (rhs <= std::numeric_limits<uint>::max()) { decNumberFromUInt32(&m_value, static_cast<uint>(rhs)); } else { char buffer[64]; uint64_to_string(rhs, buffer); decNumberFromString(&m_value, buffer, &m_context); } }
decimal32 * decimal32FromString (decimal32 *result, const char *string, decContext *set) { decContext dc; /* work */ decNumber dn; /* .. */ decContextDefault (&dc, DEC_INIT_DECIMAL32); /* no traps, please */ dc.round = set->round; /* use supplied rounding */ decNumberFromString (&dn, string, &dc); /* will round if needed */ decimal32FromNumber (result, &dn, &dc); if (dc.status != 0) { /* something happened */ decContextSetStatus (set, dc.status); /* .. pass it on */ } return result; }
static VALUE num_initialize(int argc, VALUE *argv, VALUE self) { decNumber *self_ptr; decContext *context_ptr; VALUE from, r_str, context, digits; rb_scan_args( argc, argv, "02", &from, &digits ); context = rb_funcall( cDecContext, rb_intern("new"), 1, digits ); rb_iv_set( self, "@context", context ); Data_Get_Struct(context, decContext, context_ptr); Data_Get_Struct(self, decNumber, self_ptr); if ( NIL_P(from) ) { /* decNumberFromString(dec_num_ptr, "0", &dec_context); */ } else { r_str = rb_funcall(from, rb_intern("to_s"), 0); decNumberFromString(self_ptr, StringValuePtr( r_str ), context_ptr); } return self; }
/// Convert the string presented into a form acceptable to the dec number class /// @throws exception when the format causes a problem in the number conversion. /// void DecimalDecNumber::setValue(const char *rhs) { decNumberFromString(&m_value, rhs, &m_context); const unsigned int state = decContextGetStatus(&m_context); if (state) { // See decContext.h for definition of DEC_Errors and DEC_Information if (state & DEC_Errors) { // GLCRIT(DEC_NUMBER, "decNumberFromString conversion from [%s] generated error status [%d:%s]", // rhs, state, decContextStatusToString(&m_context)); // FTHROW(InvalidArgumentException, "Attempt to create decimal from invalid string: [%s]", rhs); throw("Attempt to create decimal from invalid string"); } // GLDBUG(DEC_NUMBER, "decNumberFromString conversion from [%s] generated info status [%d:%s]", // rhs, state, decContextStatusToString(&m_context)); decContextClearStatus(&m_context, 0U); } }
int main(int argc, char *argv[]) { decQuad a; // working decQuad decNumber numa, numb; // working decNumbers decContext set; // working context char string[DECQUAD_String]; // number->string buffer if (argc<3) { // not enough words printf("Please supply two numbers for power(2*a, b).\n"); return 1; } decContextDefault(&set, DEC_INIT_DECQUAD); // initialize decQuadFromString(&a, argv[1], &set); // get a decQuadAdd(&a, &a, &a, &set); // double a decQuadToNumber(&a, &numa); // convert to decNumber decNumberFromString(&numb, argv[2], &set); decNumberPower(&numa, &numa, &numb, &set); // numa=numa**numb decQuadFromNumber(&a, &numa, &set); // back via a Quad decQuadToString(&a, string); // .. printf("power(2*%s, %s) => %s\n", argv[1], argv[2], string); return 0; } // main
/* decNumber doesn't provide support for conversions to 64-bit integer types, so do it the hard way. */ INT_TYPE DFP_TO_INT (DFP_C_TYPE x) { /* decNumber's decimal* types have the same format as C's _Decimal* types, but they have different calling conventions. */ /* TODO: Decimal float to integer conversions should raise FE_INVALID if the result value does not fit into the result type. */ IEEE_TYPE s; char buf[BUFMAX]; char *pos; decNumber qval, n1, n2; decContext context; /* Use a large context to avoid losing precision. */ decContextDefault (&context, DEC_INIT_DECIMAL128); /* Need non-default rounding mode here. */ context.round = DEC_ROUND_DOWN; HOST_TO_IEEE (x, &s); TO_INTERNAL (&s, &n1); /* Rescale if the exponent is less than zero. */ decNumberToIntegralValue (&n2, &n1, &context); /* Get a value to use for the quantize call. */ decNumberFromString (&qval, (char *) "1.", &context); /* Force the exponent to zero. */ decNumberQuantize (&n1, &n2, &qval, &context); /* Get a string, which at this point will not include an exponent. */ decNumberToString (&n1, buf); /* Ignore the fractional part. */ pos = strchr (buf, '.'); if (pos) *pos = 0; /* Use a C library function to convert to the integral type. */ return STR_TO_INT (buf, NULL, 10); }
int main(int argc, char *argv[]) { int need=3; if (argc<need+1) { // not enough words printf("Please supply %d number(s).\n", need); return 1; } { // excerpt for User's Guide starts here--------------------------| decNumber one, mtwo, hundred; // constants decNumber start, rate, years; // parameters decNumber total; // result decContext set; // working context char string[DECNUMDIGITS+14]; // conversion buffer decContextDefault(&set, DEC_INIT_BASE); // initialize set.traps=0; // no traps set.digits=25; // precision 25 decNumberFromString(&one, "1", &set); // set constants decNumberFromString(&mtwo, "-2", &set); decNumberFromString(&hundred, "100", &set); decNumberFromString(&start, argv[1], &set); // parameter words decNumberFromString(&rate, argv[2], &set); decNumberFromString(&years, argv[3], &set); decNumberDivide(&rate, &rate, &hundred, &set); // rate=rate/100 decNumberAdd(&rate, &rate, &one, &set); // rate=rate+1 decNumberPower(&rate, &rate, &years, &set); // rate=rate^years decNumberMultiply(&total, &rate, &start, &set); // total=rate*start decNumberRescale(&total, &total, &mtwo, &set); // two digits please decNumberToString(&total, string); printf("%s at %s%% for %s years => %s\n", argv[1], argv[2], argv[3], string); } //---------------------------------------------------------------| return 0; } // main
void int_to_dn(decNumber *x, int n, decContext *ctx) { char buf[12]; sprintf(buf, "%d", n); decNumberFromString(x, buf, ctx); }
const DecimalDecNumber DecimalDecNumber::round(uint32 decimalPlaces, RoundingMode mode, RoundIncrement roundIncrement) { if (isZero()) return *this; if (roundIncrement == RoundIncrement::HALF) decNumberMultiply(&m_value, &m_value, &DecimalDecNumber::TWO.m_value, &m_context); else if (roundIncrement == RoundIncrement::QUARTER) decNumberMultiply(&m_value, &m_value, &DecimalDecNumber::FOUR.m_value, &m_context); static const int BUFFER_SIZE = 256; char buffer[BUFFER_SIZE]; decNumberToString(&m_value, buffer); char * b = buffer; char * e = buffer + strlen(buffer); char * f = std::find(b, e, 'E'); if (f != e && (f+1) != e) { unpackScientificFormat(b, e, BUFFER_SIZE, 48); e = buffer + strlen(buffer); } const char * point = std::find(buffer, e, '.'); const char * firstNonZeroDigitAfterDecimal = point; while (firstNonZeroDigitAfterDecimal != e && (*firstNonZeroDigitAfterDecimal < '1' || *firstNonZeroDigitAfterDecimal > '9')) { ++firstNonZeroDigitAfterDecimal; } if (firstNonZeroDigitAfterDecimal != e) { decContext tempContext; decContextDefault(&tempContext, DEC_INIT_BASE); tempContext.traps = 0; // DecNumber rounding is expressed in significant figures; we want to round to a fixed number of decimal places. const char * firstDigit = *buffer == '-' ? (buffer+1) : buffer; const bool absValueLessThanOne = *firstDigit == '0'; if (absValueLessThanOne) { tempContext.digits = decimalPlaces - (firstNonZeroDigitAfterDecimal - point - 1); } else { tempContext.digits = decimalPlaces + (point - firstDigit); } if (tempContext.digits < 0) { decNumberFromInt32(&m_value, 0); return *this; } switch (mode) { case RoundingMode::ROUND_HALF_TO_POSITIVE_INFINITY: tempContext.round = isNegative() ? DEC_ROUND_HALF_DOWN : DEC_ROUND_HALF_UP; break; case RoundingMode::ROUND_HALF_TO_NEGATIVE_INFINITY: tempContext.round = isNegative() ? DEC_ROUND_HALF_UP : DEC_ROUND_HALF_DOWN; break; case RoundingMode::ROUND_TO_POSITIVE_INFINITY: tempContext.round = isNegative() ? DEC_ROUND_DOWN : DEC_ROUND_UP; break; case RoundingMode::ROUND_TO_NEGATIVE_INFINITY: tempContext.round = isNegative() ? DEC_ROUND_UP : DEC_ROUND_DOWN; break; case RoundingMode::ROUND_AWAY_FROM_ZERO: tempContext.round = DEC_ROUND_UP; break; case RoundingMode::ROUND_TO_ZERO: tempContext.round = DEC_ROUND_DOWN; break; case RoundingMode::ROUND_HALF_AWAY_FROM_ZERO: tempContext.round = DEC_ROUND_HALF_UP; break; case RoundingMode::ROUND_HALF_TO_ZERO: tempContext.round = DEC_ROUND_HALF_DOWN; break; case RoundingMode::ROUND_HALF_TO_EVEN: tempContext.round = DEC_ROUND_HALF_EVEN; break; default : throw("Rounding mode is not supported - rounding using default mode which is DEC_ROUND_HALF_AWAY_FROM_ZERO"); // LCRIT("Rounding mode[%d] is not supported - rounding using default mode which is DEC_ROUND_HALF_AWAY_FROM_ZERO", mode); // tempContext.round = DEC_ROUND_HALF_UP; } decNumberFromString(&m_value, buffer, &tempContext); } if (roundIncrement == RoundIncrement::HALF) decNumberDivide(&m_value, &m_value, &DecimalDecNumber::TWO.m_value, &m_context); else if (roundIncrement == RoundIncrement::QUARTER) decNumberDivide(&m_value, &m_value, &DecimalDecNumber::FOUR.m_value, &m_context); return *this; }