_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; }
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; }
void* decSingleFromInt32 (void* _res, int32_t ival) noexcept { decNumber _resnum; decNumberFromInt32 (&_resnum, ival); std::decimal::decimal32::context ctx; return decSingleFromNumber (_res, &_resnum, (decContext*)&ctx); }
DecimalDecNumber::DecimalDecNumber(int rhs) { decContextDefault(&m_context, DEC_INIT_BASE); // initialize m_context.traps = 0; // no traps, thank you m_context.digits = DECNUMDIGITS; // set precision decNumberFromInt32(&m_value, rhs); }
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; }
DecimalDecNumber power(const DecimalDecNumber &val, int32 exponent) { decNumber dExponent; decNumberFromInt32(&dExponent, exponent); DecimalDecNumber result; decNumberPower(&result.m_value, &val.m_value, &dExponent, &val.m_context); return result; }
DecimalDecNumber DecimalDecNumber::fromDecimalComponents(const int64 significand, const int32 exponent) { DecimalDecNumber number(significand); if ( exponent != 0 ) { decNumber numExponent; decNumberFromInt32( &numExponent, exponent ); decNumberScaleB( &number.m_value, &number.m_value, &numExponent, &number.m_context ); } return number; }
DEC_TYPE FUNC_NAME (_Decimal128 hi, _Decimal128 mid, _Decimal128 low) { DEC_TYPE result; /* hi = m_hi * 10^34 * mid = m_mid * 10^17 * low = m_low * 10^0 * * Note, m_hi is only at most 5 digits for int128. */ decNumber dn_hi, dn_mid, dn_low, dn_result; decNumber dn_hi_s, dn_mid_s, dn_result_s; decNumber dn_17, dn_34; decContext context; decContextDefault (&context, DEC_INIT_DECIMAL128); /* Hack, we're using 39 digits here. */ context.digits = 39; decNumberFromInt32(&dn_17, 17); decNumberFromInt32(&dn_34, 34); __DECIMAL_TO_DECNUMBER (&hi, &dn_hi, 128); __DECIMAL_TO_DECNUMBER (&mid, &dn_mid, 128); __DECIMAL_TO_DECNUMBER (&low, &dn_low, 128); /* Rotate addends into proper position. */ decNumberShift(&dn_hi_s,&dn_hi,&dn_34,&context); decNumberShift(&dn_mid_s,&dn_mid,&dn_17,&context); /* Sum the three components. */ decNumberAdd(&dn_result_s, &dn_hi_s, &dn_mid_s, &context); decNumberAdd(&dn_result, &dn_result_s, &dn_low, &context); /* Convert to the destination format. */ FUNC_CONVERT_FROM_DN (&dn_result, &result, &context); /* Don't care about exceptions here... I don't think. */ return result; }
DecimalDecNumber::DecimalDecNumber(int64 rhs) { decContextDefault(&m_context, DEC_INIT_BASE); // initialize m_context.traps = 0; // no traps, thank you m_context.digits = DECNUMDIGITS; // set precision if ( (rhs >= 0 && rhs <= std::numeric_limits<int>::max()) || (rhs < 0 && rhs >= std::numeric_limits<int>::min())) { decNumberFromInt32(&m_value, static_cast<int>(rhs)); } else { char buffer[64]; int64_to_string(rhs, buffer); decNumberFromString(&m_value, buffer, &m_context); } }
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; }
DecimalDecNumber &DecimalDecNumber::operator=(int rhs) { decNumberFromInt32(&m_value, rhs); return *this; }