/* * Convert Z = year, y = month, x = day to a valid date in X */ decNumber *dateFromYMD(decNumber *res, const decNumber *z, const decNumber *y, const decNumber *x) { if (decNumberIsSpecial(x) || decNumberIsSpecial(y) || decNumberIsSpecial(z)) return set_NaN(res); else { return build_date(res, dn_to_int(z), dn_to_int(y), dn_to_int(x)); } }
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); }
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); }
/* Return the day of the week */ static int dateExtract(decNumber *res, const decNumber *x, int *y, int *m, int *d) { if (decNumberIsSpecial(x) || extract_date(x, y, m, d)) { set_NaN(res); return 0; } return 1; }
bool DecimalDecNumber::toDecimalComponents(const DecimalDecNumber &val, int64& significand, int32& exponent) { DecimalDecNumber valCopy = val; valCopy.m_context.digits = 18; // maximum number of digits which can be represented by int64 significand // Check if decimal is NaN or infinite - we can't represent these as components if (decNumberIsSpecial( &valCopy.m_value )) { exponent = 0; significand = 0; return false; } // Minimize the size of the number the significand needs to represent decNumberReduce( &valCopy.m_value, &valCopy.m_value, &valCopy.m_context ); exponent = valCopy.m_value.exponent; decNumber numExponent; decNumberFromInt32( &numExponent, -valCopy.m_value.exponent ); decNumberScaleB( &valCopy.m_value, &valCopy.m_value, &numExponent, &valCopy.m_context ); if (::sscanf(valCopy.toString(0).c_str(), "%lld", &significand) != 1) { exponent = 0; significand = 0; return false; } return true; }
decNumber *dateFromJ(decNumber *res, const decNumber *x) { if (decNumberIsSpecial(x) || dn_lt0(x)) set_NaN(res); else { const int j = dn_to_int(x); int y, m, d; JDN2(j, &y, &m, &d); return build_date(res, y, m, d); } return res; }
/* Conversion routines from Julian days to and from dates */ decNumber *dateToJ(decNumber *res, const decNumber *x) { if (decNumberIsSpecial(x)) err: set_NaN(res); else { int y, m, d; if (extract_date(x, &y, &m, &d)) goto err; int_to_dn(res, JDN(y, m, d)); } return res; }
void date_alphamonth(enum nilop op) { decNumber x; int y, m, d; static const char mons[12*3] = "JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC"; getX(&x); if (decNumberIsSpecial(&x) || extract_date(&x, &y, &m, &d)) err(ERR_BAD_DATE); else { copy3(&(mons[3*m - 3])); } }
void date_alphaday(enum nilop op) { decNumber x; int y, m, d, dow; getX(&x); if (decNumberIsSpecial(&x) || extract_date(&x, &y, &m, &d)) err(ERR_BAD_DATE); else { dow = day_of_week(y, m, d, NULL); copy3(&("MONTUEWEDTHUFRISATSUN"[3*(dow-1)])); } }
/* Given an argument on the stack, attempt to determine the year. * If the argument is a plain integer, it is the year. * Otherwise, decode it according to the current date mode and * return the year. */ static int find_year(const decNumber *x, int *year) { int y; if (decNumberIsSpecial(x)) return -1; if (is_int(x)) { y = dn_to_int(x); if (check_date(y, 1, 1)) return -1; } else if (extract_date(x, &y, NULL, NULL)) return -1; *year = y; return 0; }
// ------------------------------------- // comparison function. Returns // Not Comparable : -2 // < : -1 // == : 0 // > : +1 int32_t DigitList::compare(const DigitList &other) { decNumber result; int32_t savedDigits = fContext.digits; fContext.digits = 1; uprv_decNumberCompare(&result, this->fDecNumber, other.fDecNumber, &fContext); fContext.digits = savedDigits; if (decNumberIsZero(&result)) { return 0; } else if (decNumberIsSpecial(&result)) { return -2; } else if (result.bits & DECNEG) { return -1; } else { return 1; } }
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; }
/** * Return true if the number represented by this object can fit into * a long. */ UBool DigitList::fitsIntoInt64(UBool ignoreNegativeZero) /*const*/ { if (decNumberIsSpecial(this->fDecNumber)) { // NaN or Infinity. Does not fit in int32. return FALSE; } uprv_decNumberTrim(this->fDecNumber); if (fDecNumber->exponent < 0) { // Number contains fraction digits. return FALSE; } if (decNumberIsZero(this->fDecNumber) && !ignoreNegativeZero && (fDecNumber->bits & DECNEG) != 0) { // Negative Zero, not ingored. Cannot represent as a long. return FALSE; } if (getUpperExponent() < 19) { // The number is 18 or fewer digits. // The max and min int64 are 19 digts, so this number fits. // This is the common case. return TRUE; } // TODO: Should cache these constants; construction is relatively costly. // But not of huge consequence; they're only needed for 19 digit ints. UErrorCode status = U_ZERO_ERROR; DigitList min64; min64.set("-9223372036854775808", status); if (this->compare(min64) < 0) { return FALSE; } DigitList max64; max64.set("9223372036854775807", status); if (this->compare(max64) > 0) { return FALSE; } if (U_FAILURE(status)) { return FALSE; } return true; }