_RETURN_TYPE INTERNAL_FUNCTION_NAME (DEC_TYPE x) { DEC_TYPE result; decContext context; decNumber dn_result; decNumber dn_x; decNumber dn_absx; decNumber dn_logx; decNumber dn_one; decNumber dn_cmp; enum rounding round; FUNC_CONVERT_TO_DN (&x, &dn_x); if (decNumberIsZero (&dn_x)) { DFP_EXCEPT (FE_INVALID); DFP_ERRNO (EDOM); return _FBLOG0; } if (decNumberIsInfinite (&dn_x)) { DFP_EXCEPT (FE_INVALID); DFP_ERRNO (EDOM); return decNumberIsNegative (&dn_x) ? _MIN_VALUE : _MAX_VALUE; } if (decNumberIsNaN (&dn_x)) { DFP_EXCEPT (FE_INVALID); DFP_ERRNO (EDOM); return _FBLOGNAN; } decContextDefault (&context, DEFAULT_CONTEXT); decNumberAbs (&dn_absx, &dn_x, &context); /* For DFP, we use radix 10 instead of whatever FLT_RADIX happens to be */ decNumberLog10 (&dn_logx, &dn_absx, &context); /* Capture the case where truncation will return the wrong result, by rounding up if -1.0 < x < 1.0 */ round = DEC_ROUND_DOWN; decNumberFromInt32 (&dn_one, 1); decNumberCompare (&dn_cmp, &dn_x, &dn_one, &context); if (-decNumberIsNegative(&dn_cmp)) { decNumberFromInt32 (&dn_one, -1); decNumberCompare (&dn_cmp, &dn_x, &dn_one, &context); if (!decNumberIsNegative(&dn_cmp) && !decNumberIsZero(&dn_cmp)) round = DEC_ROUND_UP; } context.round = round; decNumberToIntegralValue (&dn_result, &dn_logx, &context); FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); /* Use _Decimal* to int casting. */ return (_RETURN_TYPE) result; }

decNumber *decNumberAGM(decNumber *res, const decNumber *x, const decNumber *y) { int n; decNumber a, g, t, u; if (decNumberIsNegative(x) || decNumberIsNegative(y)) goto nan; if (decNumberIsSpecial(x) || decNumberIsSpecial(y)) { if (decNumberIsNaN(x) || decNumberIsNaN(y)) goto nan; if (dn_eq0(x) || dn_eq0(y)) goto nan; return set_inf(res); } decNumberCopy(&a, x); decNumberCopy(&g, y); for (n=0; n<1000; n++) { if (relative_error(&a, &g, &const_1e_32)) return decNumberCopy(res, &a); dn_add(&t, &a, &g); dn_div2(&u, &t); dn_multiply(&t, &a, &g); if (dn_eq0(&t)) return decNumberZero(res); dn_sqrt(&g, &t); decNumberCopy(&a, &u); } nan: return set_NaN(res); }

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

DEC_TYPE INTERNAL_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; decNumber dn_tmp; decNumber dn_log10; decNumber dn_one; decNumber dn_cmp; enum rounding round; FUNC_CONVERT_TO_DN (&x, &dn_x); if (decNumberIsNaN (&dn_x)) return x+x; if (decNumberIsInfinite (&dn_x)) /* +-Inf: Inf */ return DEC_INFINITY; if (decNumberIsZero (&dn_x)) /* Pole Error if x==0 */ { DFP_ERRNO (ERANGE); DFP_EXCEPT (FE_DIVBYZERO); return -DFP_HUGE_VAL; } if (decNumberIsInfinite (&dn_x) && decNumberIsNegative (&dn_x)) return -x; decContextDefault (&context, DEFAULT_CONTEXT); decNumberAbs (&dn_tmp, &dn_x, &context); /* For DFP, we use radix 10 instead of whatever FLT_RADIX happens to be */ decNumberLog10 (&dn_log10, &dn_tmp, &context); /* Capture the case where truncation will return the wrong result, by rounding up if -1.0 < x < 1.0 */ round = DEC_ROUND_DOWN; decNumberFromInt32 (&dn_one, 1); decNumberCompare (&dn_cmp, &dn_x, &dn_one, &context); if (-decNumberIsNegative(&dn_cmp)) { decNumberFromInt32 (&dn_one, -1); decNumberCompare (&dn_cmp, &dn_x, &dn_one, &context); if (!decNumberIsNegative(&dn_cmp) && !decNumberIsZero(&dn_cmp)) round = DEC_ROUND_UP; } context.round = round; decNumberToIntegralValue (&dn_result, &dn_log10, &context); FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); return result; }

/** * convert this number to an int64_t. Truncate if there is a fractional part. * Return zero if the number cannot be represented. */ int64_t DigitList::getInt64() /*const*/ { if(fHave==kInt64) { return fUnion.fInt64; } // Truncate if non-integer. // Return 0 if out of range. // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits) // if (fDecNumber->digits + fDecNumber->exponent > 19) { // Overflow, absolute value too big. return 0; } // The number of integer digits may differ from the number of digits stored // in the decimal number. // for 12.345 numIntDigits = 2, number->digits = 5 // for 12E4 numIntDigits = 6, number->digits = 2 // The conversion ignores the fraction digits in the first case, // and fakes up extra zero digits in the second. // TODO: It would be faster to store a table of powers of ten to multiply by // instead of looping over zero digits, multiplying each time. int32_t numIntDigits = fDecNumber->digits + fDecNumber->exponent; uint64_t value = 0; for (int32_t i = 0; i < numIntDigits; i++) { // Loop is iterating over digits starting with the most significant. // Numbers are stored with the least significant digit at index zero. int32_t digitIndex = fDecNumber->digits - i - 1; int32_t v = (digitIndex >= 0) ? fDecNumber->lsu[digitIndex] : 0; value = value * (uint64_t)10 + (uint64_t)v; } if (decNumberIsNegative(fDecNumber)) { value = ~value; value += 1; } int64_t svalue = (int64_t)value; // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of // overflow can't wrap too far. The test will also fail -0, but // that does no harm; the right answer is 0. if (numIntDigits == 19) { if (( decNumberIsNegative(fDecNumber) && svalue>0) || (!decNumberIsNegative(fDecNumber) && svalue<0)) { svalue = 0; } } return svalue; }

static DEC_TYPE IEEE_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; decNumber dn_two; DEC_TYPE two = DFP_CONSTANT(2.0); FUNC_CONVERT_TO_DN (&two, &dn_two); FUNC_CONVERT_TO_DN (&x, &dn_x); if (decNumberIsNaN (&dn_x)) return x+x; if (decNumberIsInfinite (&dn_x) ) return decNumberIsNegative (&dn_x) ? DFP_CONSTANT(0.0) : x; decContextDefault (&context, DEFAULT_CONTEXT); /* decNumberPow (&dn_result, &dn_two, &dn_x, &context); */ decNumberPower (&dn_result, &dn_two, &dn_x, &context); FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); if(context.status & DEC_Overflow) DFP_EXCEPT (FE_OVERFLOW); return result; }

void cmplxAGM(decNumber *rx, decNumber *ry, const decNumber *a, const decNumber *b, const decNumber *c, const decNumber *d) { decNumber x1, x2, y1, y2, t1, t2, u1, u2; int n; if (decNumberIsSpecial(a) || decNumberIsSpecial(b) || decNumberIsSpecial(c) || decNumberIsSpecial(d)) { goto nan; } cmplxCopy(&x1, &x2, a, b); cmplxCopy(&y1, &y2, c, d); for (n=0; n<1000; n++) { cmplxSubtract(&t1, &t2, &x1, &x2, &y1, &y2); cmplxR(&u1, &t1, &t2); dn_compare(&u2, &u1, &const_1e_32); if (decNumberIsNegative(&u2)) { cmplxCopy(rx, ry, &x1, &x2); return; } cmplxAdd(&t1, &t2, &x1, &x2, &y1, &y2); cmplxDiv2(&u1, &u2, &t1, &t2); cmplxMultiply(&t1, &t2, &x1, &x2, &y1, &y2); cmplxSqrt(&y1, &y2, &t1, &t2); cmplxCopy(&x1, &x2, &u1, &u2); } nan: cmplx_NaN(rx, ry); }

static DEC_TYPE IEEE_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; decNumber dn_one; decNumber dn_exponent; DEC_TYPE one = DFP_CONSTANT(1.0); FUNC_CONVERT_TO_DN(&x, &dn_x); FUNC_CONVERT_TO_DN(&one, &dn_one); if (decNumberIsNaN (&dn_x)) return x+x; if (decNumberIsInfinite (&dn_x)) return decNumberIsNegative (&dn_x) ? DFP_CONSTANT(-1.0) : x; decContextDefault(&context, DEFAULT_CONTEXT); decNumberExp(&dn_exponent, &dn_x, &context); decNumberSubtract(&dn_result, &dn_exponent, &dn_one, &context); FUNC_CONVERT_FROM_DN(&dn_result, &result, &context); if (context.status & DEC_Overflow) DFP_EXCEPT (FE_OVERFLOW); return result; }

static DEC_TYPE IEEE_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; FUNC_CONVERT_TO_DN(&x, &dn_x); if (decNumberIsNaN (&dn_x)) return x+x; if (decNumberIsZero (&dn_x)) /* If x == 0: Pole Error */ { DFP_EXCEPT (FE_DIVBYZERO); return -DFP_HUGE_VAL; } if (decNumberIsNegative (&dn_x)) /* If x < 0,: Domain Error */ { DFP_EXCEPT (FE_INVALID); return DFP_NAN; } if (decNumberIsInfinite (&dn_x)) return x; decContextDefault (&context, DEFAULT_CONTEXT); decNumberLn(&dn_result, &dn_x, &context); FUNC_CONVERT_FROM_DN(&dn_result, &result, &context); return result; }

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; }

static void decimal_from_decnumber (REAL_VALUE_TYPE *r, decNumber *dn, decContext *context) { memset (r, 0, sizeof (REAL_VALUE_TYPE)); r->cl = rvc_normal; if (decNumberIsZero (dn)) r->cl = rvc_zero; if (decNumberIsNaN (dn)) r->cl = rvc_nan; if (decNumberIsInfinite (dn)) r->cl = rvc_inf; if (context->status & DEC_Overflow) r->cl = rvc_inf; if (decNumberIsNegative (dn)) r->sign = 1; r->decimal = 1; if (r->cl != rvc_normal) return; decContextDefault (context, DEC_INIT_DECIMAL128); context->traps = 0; decimal128FromNumber ((decimal128 *) r->sig, dn, context); }

/* Take a matrix descriptor and return the base register number. * Optionally return the number of rows and columns in the matrix. * Optionally return the sign of the initial descriptor as well. */ static int matrix_decompose(const decNumber *x, int *rows, int *cols, int *up) { decNumber ax, y; unsigned int n, base; int r, c, u; if (decNumberIsNegative(x)) { dn_abs(&ax, x); x = &ax; u = 0; } else u = 1; if (up) *up = u; dn_mulpow10(&y, x, 4); n = dn_to_int(&y); base = n / 10000; c = n % 100; r = (n / 100) % 100; if (c == 0) c = r; if (! matrix_range_check(base, r, c)) return -1; if (c == 0) { err(ERR_BAD_PARAM); return -1; } if (rows) *rows = r; if (cols) *cols = c; return base; }

static inline int dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) { IEEE_TYPE a, b; decContext context; decNumber arg1, arg2, res; int result; HOST_TO_IEEE (arg_a, &a); HOST_TO_IEEE (arg_b, &b); decContextDefault (&context, CONTEXT_INIT); context.round = CONTEXT_ROUND; TO_INTERNAL (&a, &arg1); TO_INTERNAL (&b, &arg2); /* Perform the comparison. */ op (&res, &arg1, &arg2, &context); if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) DFP_RAISE (0); if (decNumberIsNegative (&res)) result = -1; else if (decNumberIsZero (&res)) result = 0; else result = 1; return result; }

DEC_TYPE INTERNAL_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; FUNC_CONVERT_TO_DN (&x, &dn_x); decContextDefault (&context, DEFAULT_CONTEXT); if (decNumberIsInfinite (&dn_x)) { if (decNumberIsNegative (&dn_x)) result = -M_PI_2dl; else result = M_PI_2dl; } else { decNumberAtan (&dn_result, &dn_x, &context); FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); } return result; }

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; }

/** * Currently, getDouble() depends on atof() to do its conversion. * * WARNING!! * This is an extremely costly function. ~1/2 of the conversion time * can be linked to this function. */ double DigitList::getDouble() const { // TODO: fix thread safety. Can probably be finessed some by analyzing // what public const functions can see which DigitLists. // Like precompute fDouble for DigitLists coming in from a parse // or from a Formattable::set(), but not for any others. if (fHaveDouble) { return fDouble; } DigitList *nonConstThis = const_cast<DigitList *>(this); if (isZero()) { nonConstThis->fDouble = 0.0; if (decNumberIsNegative(fDecNumber)) { nonConstThis->fDouble /= -1; } } else if (isInfinite()) { if (std::numeric_limits<double>::has_infinity) { nonConstThis->fDouble = std::numeric_limits<double>::infinity(); } else { nonConstThis->fDouble = std::numeric_limits<double>::max(); } if (!isPositive()) { nonConstThis->fDouble = -fDouble; } } else { MaybeStackArray<char, MAX_DBL_DIGITS+18> s; // Note: 14 is a magic constant from the decNumber library documentation, // the max number of extra characters beyond the number of digits // needed to represent the number in string form. Add a few more // for the additional digits we retain. // Round down to appx. double precision, if the number is longer than that. // Copy the number first, so that we don't modify the original. if (getCount() > MAX_DBL_DIGITS + 3) { DigitList numToConvert(*this); numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. numToConvert.round(MAX_DBL_DIGITS+3); uprv_decNumberToString(numToConvert.fDecNumber, s); // TODO: how many extra digits should be included for an accurate conversion? } else { uprv_decNumberToString(this->fDecNumber, s); } U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); loadDecimalChar(); if (gDecimal != '.') { char *decimalPt = strchr(s, '.'); if (decimalPt != NULL) { *decimalPt = gDecimal; } } char *end = NULL; nonConstThis->fDouble = uprv_strtod(s, &end); } nonConstThis->fHaveDouble = TRUE; return fDouble; }

int INTERNAL_FUNCTION_NAME (DEC_TYPE x, DEC_TYPE y) { decNumber dn_x; decNumber dn_y; decNumber dn_result; decContext context; FUNC_CONVERT_TO_DN(&x, &dn_x); FUNC_CONVERT_TO_DN(&y, &dn_y); if(decNumberIsNaN(&dn_x) || decNumberIsNaN(&dn_y)) return 0; decNumberCompare (&dn_result, &dn_x, &dn_y, &context); return (-decNumberIsNegative (&dn_result)) || (!decNumberIsNegative (&dn_result) && !decNumberIsZero (&dn_result)); }

DEC_TYPE INTERNAL_FUNCTION_NAME (DEC_TYPE x, DEC_TYPE y) { decContext context; DEC_TYPE result; decNumber dn_x; decNumber dn_y; FUNC_CONVERT_TO_DN (&x, &dn_x); FUNC_CONVERT_TO_DN (&y, &dn_y); if(decNumberIsNegative (&dn_x) != decNumberIsNegative (&dn_y)) decNumberNegate (&dn_x); decContextDefault (&context, DEFAULT_CONTEXT); FUNC_CONVERT_FROM_DN (&dn_x, &result, &context); return result; }

int64_t DigitList::getInt64() /*const*/ { // Round if non-integer. (Truncate or round?) // Return 0 if out of range. // Range of in64_t is -9223372036854775808 to 9223372036854775807 (19 digits) // if (fDecNumber->digits + fDecNumber->exponent > 19) { // Overflow, absolute value too big. return 0; } decNumber *workingNum = fDecNumber; if (fDecNumber->exponent != 0) { // Force to an integer, with zero exponent, rounding if necessary. DigitList copy(*this); DigitList zero; uprv_decNumberQuantize(copy.fDecNumber, copy.fDecNumber, zero.fDecNumber, &fContext); workingNum = copy.fDecNumber; } uint64_t value = 0; int32_t numDigits = workingNum->digits; for (int i = numDigits-1; i>=0 ; --i) { int v = workingNum->lsu[i]; value = value * (uint64_t)10 + (uint64_t)v; } if (decNumberIsNegative(workingNum)) { value = ~value; value += 1; } int64_t svalue = (int64_t)value; // Check overflow. It's convenient that the MSD is 9 only on overflow, the amount of // overflow can't wrap too far. The test will also fail -0, but // that does no harm; the right answer is 0. if (numDigits == 19) { if (( decNumberIsNegative(fDecNumber) && svalue>0) || (!decNumberIsNegative(fDecNumber) && svalue<0)) { svalue = 0; } } return svalue; }

/** * Currently, getDouble() depends on strtod() to do its conversion. * * WARNING!! * This is an extremely costly function. ~1/2 of the conversion time * can be linked to this function. */ double DigitList::getDouble() const { { Mutex mutex; if (fHave == kDouble) { return fUnion.fDouble; } } double tDouble = 0.0; if (isZero()) { tDouble = 0.0; if (decNumberIsNegative(fDecNumber)) { tDouble /= -1; } } else if (isInfinite()) { if (std::numeric_limits<double>::has_infinity) { tDouble = std::numeric_limits<double>::infinity(); } else { tDouble = std::numeric_limits<double>::max(); } if (!isPositive()) { tDouble = -tDouble; //this was incorrectly "-fDouble" originally. } } else { MaybeStackArray<char, MAX_DBL_DIGITS+18> s; // Note: 14 is a magic constant from the decNumber library documentation, // the max number of extra characters beyond the number of digits // needed to represent the number in string form. Add a few more // for the additional digits we retain. // Round down to appx. double precision, if the number is longer than that. // Copy the number first, so that we don't modify the original. if (getCount() > MAX_DBL_DIGITS + 3) { DigitList numToConvert(*this); numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. numToConvert.round(MAX_DBL_DIGITS+3); uprv_decNumberToString(numToConvert.fDecNumber, s.getAlias()); // TODO: how many extra digits should be included for an accurate conversion? } else { uprv_decNumberToString(this->fDecNumber, s.getAlias()); } U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); char *end = NULL; tDouble = decimalStrToDouble(s.getAlias(), &end); } { Mutex mutex; DigitList *nonConstThis = const_cast<DigitList *>(this); nonConstThis->internalSetDouble(tDouble); } return tDouble; }

/* Convert a decimal real to a date. * We have to honour the current date mode and make sure that things * don't go out of range. */ static int extract_date(const decNumber *x, int *year, int *month, int *day) { int ip, fp, y, m, d; decNumber z, a; int neg = 1; if (is_intmode()) return 1; if (decNumberIsNegative(x)) { dn_minus(&z, x); neg = -1; } else { decNumberCopy(&z, x); } decNumberTrunc(&a, &z); // a = iii z = iii.ffrrrr ip = dn_to_int(&a); dn_subtract(&a, &z, &a); // a = .ffrrrr dn_mul100(&z, &a); // z = ff.rrrr decNumberTrunc(&a, &z); // a = ff fp = dn_to_int(&a); dn_subtract(&z, &z, &a); // z = .rrrr switch (UState.date_mode) { default: case DATE_YMD: y = ip; m = fp; dn_mul100(&a, &z); decNumberTrunc(&z, &a); d = dn_to_int(&z); break; case DATE_DMY: d = ip; m = fp; goto year; case DATE_MDY: m = ip; d = fp; year: dn_mulpow10(&a, &z, 4); decNumberTrunc(&z, &a); y = dn_to_int(&z); break; } /* Make sense of things */ y *= neg; if (year != NULL) *year = y; if (month != NULL) *month = m; if (day != NULL) *day = d; return check_date(y, m, d); }

static DEC_TYPE IEEE_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result, one, temp; decNumber dn_x, dn_temp, dn_one; /* int comp;*/ one=DFP_CONSTANT(1.0); FUNC_CONVERT_TO_DN (&one, &dn_one); FUNC_CONVERT_TO_DN (&x, &dn_x); /* Handle NaN and early exit for x==0 */ if (decNumberIsNaN (&dn_x) || decNumberIsZero (&dn_x)) return x + x; decContextDefault (&context, DEFAULT_CONTEXT); decNumberAbs (&dn_temp, &dn_x, &context); FUNC_CONVERT_FROM_DN (&dn_temp, &temp, &context); if(temp==one) { /* |x| == 1 -> Pole Error */ DFP_EXCEPT (FE_DIVBYZERO); return decNumberIsNegative(&dn_x) ? -DFP_HUGE_VAL:DFP_HUGE_VAL; } else if (temp>one) { /* |x| > 1 -> Domain Error (this handles +-Inf too) */ DFP_EXCEPT (FE_INVALID); return DFP_NAN; } // comp = decCompare (&dn_temp, &dn_one); // switch (comp) // { // case 0: /* |x| == 1 -> Pole Error */ // DFP_EXCEPT (FE_DIVBYZERO); // return decNumberIsNegative(&dn_x) ? -DFP_HUGE_VAL:DFP_HUGE_VAL; // case 1: /* |x| > 1 -> Domain Error (this handles +-Inf too) */ // DFP_EXCEPT (FE_INVALID); // return DFP_NAN; // } /* Using trig identity: atanh(x) = 1/2 * log((1+x)/(1-x)) */ decNumberAdd (&dn_result, &dn_one, &dn_x, &context); decNumberSubtract (&dn_temp, &dn_one, &dn_x, &context); decNumberDivide (&dn_result, &dn_result, &dn_temp, &context); decNumberLn (&dn_result, &dn_result, &context); decNumberAdd (&dn_temp, &dn_one, &dn_one, &context); /* 2 */ decNumberDivide (&dn_result, &dn_result, &dn_temp, &context); FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); return result; }

// 60 bytes decNumber *decNumberSign(decNumber *r, const decNumber *x) { const decNumber *z; if (decNumberIsNaN(x)) z = x; else if (dn_eq0(x)) z = &const_0; else if (decNumberIsNegative(x)) z = &const__1; else z = &const_1; return decNumberCopy(r, z); }

static DEC_TYPE IEEE_FUNCTION_NAME (DEC_TYPE x) { decContext context; decNumber dn_result; DEC_TYPE result; decNumber dn_x; decNumber dn_sum; decNumber dn_one; DEC_TYPE one = DFP_CONSTANT(1.0); FUNC_CONVERT_TO_DN (&x, &dn_x); FUNC_CONVERT_TO_DN (&one, &dn_one); /* For NaN, 0, or +Inf, just return x */ if (decNumberIsNaN (&dn_x) || decNumberIsZero (&dn_x) || (decNumberIsInfinite (&dn_x) && !decNumberIsNegative (&dn_x))) return x+x; decContextDefault(&context, DEFAULT_CONTEXT); decNumberAdd(&dn_sum, &dn_x, &dn_one, &context); if (decNumberIsZero(&dn_sum)) /* Pole Error if x was -1 */ { DFP_EXCEPT (FE_DIVBYZERO); return -DFP_HUGE_VAL; } if (decNumberIsNegative(&dn_sum)) /* Domain Error if x < -1 */ { DFP_EXCEPT (FE_INVALID); return DFP_NAN; } decNumberLn(&dn_result, &dn_sum, &context); FUNC_CONVERT_FROM_DN(&dn_result, &result, &context); return result; }

int PREFIXED_FUNCTION_NAME (DEC_TYPE x, DEC_TYPE y) { decNumber dn_x, dn_y, result; decContext context; decContextDefault(&context, DEFAULT_CONTEXT); FUNC_CONVERT_TO_DN(&x, &dn_x); FUNC_CONVERT_TO_DN(&y, &dn_y); if(decNumberIsNaN(&dn_x) || decNumberIsNaN(&dn_y)) return -1; decNumberCompare(&result, &dn_x, &dn_y, &context); return !decNumberIsNegative(&result) && !decNumberIsZero(&result); }

void convertToIntX<int64>(const decNumber* pDecNum, decContext* pContext, int64& result) { static const uint64 s_arrPowerOfTen[19] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000ULL, 100000000000ULL, 1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL }; if (decNumberIsSpecial(pDecNum)) { char sNumber[1024]; throw("Attempt to get an integer from invalid number"); } else if (pDecNum->exponent != 0) { char sNumber[1024]; // FTHROW(InvalidArgumentException, "Unsupported exponent %d, only zero exponent is supported, number %s", pDecNum->exponent, decNumberToString(pDecNum, sNumber)); throw("Unsupported exponent , only zero exponent is supported, number "); } else if (pDecNum->digits > (int)(sizeof(s_arrPowerOfTen)/sizeof(*s_arrPowerOfTen))) { char sNumber[1024]; // FTHROW(InvalidArgumentException, "Overflow during conversion, number of digits is %d, number %s", pDecNum->digits, decNumberToString(pDecNum, sNumber)); throw("Overflow during conversion, number of digits is number "); } const decNumberUnit* pDigit = pDecNum->lsu; uint64 nUnsignedResult = 0; const bool isNegative = decNumberIsNegative(pDecNum); const uint64 nMaxValue = isNegative ? -std::numeric_limits<int64>::min() : std::numeric_limits<int64>::max(); for (int i = 0; i < pDecNum->digits; ++pDigit, i += DECDPUN) { const uint64 nPrev = nUnsignedResult; // to be able to check on 'overflow' nUnsignedResult += *pDigit * s_arrPowerOfTen[i]; if ((nUnsignedResult < nPrev) || (nUnsignedResult > nMaxValue)) { char sNumber[1024]; throw("Overflow during conversion, step"); // FTHROW(InvalidArgumentException, "Overflow during conversion, step %d (%llu, %llu, %llu), number %s", // i, nUnsignedResult, nPrev, nMaxValue, decNumberToString(pDecNum, sNumber)); } } result = isNegative ? -((int64)nUnsignedResult) : (int64)nUnsignedResult; }

/* Compute a factorial. * Currently, only for positive integer arguments. Needs to be extended * to a full gamma function. */ decNumber *decNumberFactorial(decNumber *r, const decNumber *x, decContext *ctx) { decNumber y, const_1; int_to_dn(&const_1, 1, ctx); decNumberCopy(&y, x); if (!decNumberIsNegative(x) || decNumberIsZero(x)) { decNumberCopy(r, &const_1); for (;;) { if (decNumberIsZero(&y)) break; if (decNumberIsInfinite(r)) break; decNumberMultiply(r, r, &y, ctx); decNumberSubtract(&y, &y, &const_1, ctx); } } return r; }

/** * Currently, getDouble() depends on strtod() to do its conversion. * * WARNING!! * This is an extremely costly function. ~1/2 of the conversion time * can be linked to this function. */ double DigitList::getDouble() const { static char gDecimal = 0; char decimalSeparator; { Mutex mutex; if (fHave == kDouble) { return fUnion.fDouble; } else if(fHave == kInt64) { return (double)fUnion.fInt64; } decimalSeparator = gDecimal; } if (decimalSeparator == 0) { // We need to know the decimal separator character that will be used with strtod(). // Depends on the C runtime global locale. // Most commonly is '.' // TODO: caching could fail if the global locale is changed on the fly. char rep[MAX_DIGITS]; sprintf(rep, "%+1.1f", 1.0); decimalSeparator = rep[2]; } double tDouble = 0.0; if (isZero()) { tDouble = 0.0; if (decNumberIsNegative(fDecNumber)) { tDouble /= -1; } } else if (isInfinite()) { if (std::numeric_limits<double>::has_infinity) { tDouble = std::numeric_limits<double>::infinity(); } else { tDouble = std::numeric_limits<double>::max(); } if (!isPositive()) { tDouble = -tDouble; //this was incorrectly "-fDouble" originally. } } else { MaybeStackArray<char, MAX_DBL_DIGITS+18> s; // Note: 14 is a magic constant from the decNumber library documentation, // the max number of extra characters beyond the number of digits // needed to represent the number in string form. Add a few more // for the additional digits we retain. // Round down to appx. double precision, if the number is longer than that. // Copy the number first, so that we don't modify the original. if (getCount() > MAX_DBL_DIGITS + 3) { DigitList numToConvert(*this); numToConvert.reduce(); // Removes any trailing zeros, so that digit count is good. numToConvert.round(MAX_DBL_DIGITS+3); uprv_decNumberToString(numToConvert.fDecNumber, s); // TODO: how many extra digits should be included for an accurate conversion? } else { uprv_decNumberToString(this->fDecNumber, s); } U_ASSERT(uprv_strlen(&s[0]) < MAX_DBL_DIGITS+18); if (decimalSeparator != '.') { char *decimalPt = strchr(s, '.'); if (decimalPt != NULL) { *decimalPt = decimalSeparator; } } char *end = NULL; tDouble = uprv_strtod(s, &end); } { Mutex mutex; DigitList *nonConstThis = const_cast<DigitList *>(this); nonConstThis->internalSetDouble(tDouble); gDecimal = decimalSeparator; } return tDouble; }

/* Smart CDF helper routine that return three values */ void cdf_Q_helper(enum nilop op) { decNumber a, b, t, u, x2, d, absx, x; int i; getX(&x); dn_abs(&absx, &x); if (dn_lt(&absx, &const_2_326)) { decNumberSquare(&x2, &absx); decNumberCopy(&t, &absx); decNumberCopy(&a, &absx); decNumberCopy(&d, &const_3); for (i=0;i<500; i++) { dn_multiply(&u, &t, &x2); dn_divide(&t, &u, &d); dn_add(&u, &a, &t); if (dn_eq(&u, &a)) break; decNumberCopy(&a, &u); dn_p2(&d, &d); } decNumberCopy(&b, &const_0_5); if (decNumberIsNegative(&x)) dn_minus(&a, &a); } else { const decNumber *nom, *extra, *sub; //dn_minus(&x2, &absx); //n = ceil(extra + nom / (|x| - sub)) if (is_usrdblmode()) { sub = &const_1_5; nom = &const_300; extra = &const_8; } else { sub = &const_1_3; nom = &const_100; extra = &const_4; } dn_subtract(&b, &absx, sub); dn_divide(&t, nom, &b); dn_add(&u, &t, extra); decNumberCeil(&b, &u); decNumberZero(&t); do { dn_add(&u, &x, &t); dn_divide(&t, &b, &u); dn_dec(&b); } while (! dn_eq0(&b)); dn_add(&u, &t, &x); decNumberRecip(&a, &u); if (decNumberIsNegative(&a)) { dn_minus(&a, &a); decNumberZero(&b); } else { dn_1(&b); dn_minus(&a, &a); } } pdf_Q(&t, &x); setXYZ(&t, &a, &b); }

void dn_elliptic(decNumber *sn, decNumber *cn, decNumber *dn, const decNumber *u, const decNumber *m) { decNumber a, b, e, f, g; decNumber s_n, c_n, d_n; decNumber MU[ELLIPTIC_N], NU[ELLIPTIC_N], C[ELLIPTIC_N], D[ELLIPTIC_N]; decNumber sin_umu, cos_umu, t, r; int n = 0; #define mu(n) (MU + (n)) #define nu(n) (NU + (n)) #define c(n) (C + (n)) #define d(n) (D + (n)) if (sn == NULL) sn = &s_n; if (cn == NULL) cn = &c_n; if (dn == NULL) dn = &d_n; dn_abs(&a, m); if (dn_lt(&const_1, &a)) { cmplx_NaN(sn, cn); set_NaN(dn); return; } if (dn_lt(&a, &const_1e_32)) { dn_sincos(u, sn, cn); dn_1(dn); return; } dn_m1(&a, m); if (dn_abs_lt(&a, &const_1e_32)) { dn_sinhcosh(u, &a, &b); decNumberRecip(cn, &b); dn_multiply(sn, &a, cn); decNumberCopy(dn, cn); return; } dn_1(mu(0)); dn_1m(&a, m); dn_sqrt(nu(0), &a); for (;;) { dn_add(&g, mu(n), nu(n)); dn_abs(&a, &g); dn_mulpow10(&b, &a, 32); dn_mul2(&a, &b); dn_subtract(&e, mu(n), nu(n)); dn_abs(&f, &e); if (dn_gt(&a, &f)) break; dn_div2(mu(n+1), &g); dn_multiply(&a, mu(n), nu(n)); dn_sqrt(nu(n+1), &a); n++; if (n >= ELLIPTIC_N-1) break; } dn_multiply(&a, u, mu(n)); dn_sincos(&a, &sin_umu, &cos_umu); if (dn_abs_lt(&sin_umu, dn_abs(&b, &cos_umu))) dn_divide(&t, &sin_umu, &cos_umu); else dn_divide(&t, &cos_umu, &sin_umu); dn_multiply(c(n), mu(n), &t); dn_1(d(n)); while (n > 0) { n--; dn_multiply(c(n), d(n+1), c(n+1)); decNumberSquare(&a, c(n+1)); dn_divide(&r, &a, mu(n+1)); dn_add(&a, &r, nu(n)); dn_add(&b, &r, mu(n)); dn_divide(d(n), &a, &b); } cmplxAbs(&f, &b, &const_1, c(0)); if (decNumberIsNegative(&e)) { dn_1m(&a, m); dn_sqrt(&g, &a); dn_divide(dn, &g, d(0)); dn_divide(cn, dn, &f); if (decNumberIsNegative(&cos_umu)) dn_minus(cn, cn); dn_divide(&a, c(0), &g); dn_multiply(sn, cn, &a); } else { decNumberCopy(dn, d(0)); dn_divide(sn, &const_1, &f); if (decNumberIsNegative(&sin_umu)) dn_minus(sn, sn); dn_multiply(cn, c(0), sn); } #undef mu #undef nu #undef c #undef d }