in csharp/EPAM.Deltix.DFP/DotNetImpl.cs [408:536]
public static UInt64 Round(UInt64 value, int n, RoundingMode roundType)
{
if (!IsFinite(value))
return value;
if (n > MaxExponent)
return value;
if (n < MinExponent)
return Zero;
BID_UINT64 partsSignMask;
int partsExponent;
BID_UINT64 partsCoefficient;
// DotNetReImpl.unpack_BID64(out partsSignMask, out partsExponent, out partsCoefficient, value);
{ // Copy-paste the toParts method for speedup
partsSignMask = value & 0x8000000000000000UL;
if ((value & DotNetReImpl.SPECIAL_ENCODING_MASK64) == DotNetReImpl.SPECIAL_ENCODING_MASK64)
{
//if ((value & DotNetReImpl.INFINITY_MASK64) == DotNetReImpl.INFINITY_MASK64) - Non finite values are already checked
//{
// partsExponent = 0;
// partsCoefficient = value & 0xfe03ffffffffffffUL;
// if ((value & 0x0003ffffffffffffUL) >= 1000000000000000UL)
// partsCoefficient = value & 0xfe00000000000000UL;
// if ((value & DotNetReImpl.NAN_MASK64) == DotNetReImpl.INFINITY_MASK64)
// partsCoefficient = value & DotNetReImpl.SINFINITY_MASK64;
// return 0; // NaN or Infinity
//} else
{
// Check for non-canonical values.
BID_UINT64 coeff = (value & DotNetReImpl.LARGE_COEFF_MASK64) | DotNetReImpl.LARGE_COEFF_HIGH_BIT64;
// check for non-canonical values
if (coeff >= 10000000000000000UL)
coeff = 0;
partsCoefficient = coeff;
// get exponent
BID_UINT64 tmp = value >> DotNetReImpl.EXPONENT_SHIFT_LARGE64;
partsExponent = (int)(tmp & DotNetReImpl.EXPONENT_MASK64);
}
}
else
{
// exponent
BID_UINT64 tmp = value >> DotNetReImpl.EXPONENT_SHIFT_SMALL64;
partsExponent = (int)(tmp & DotNetReImpl.EXPONENT_MASK64);
// coefficient
partsCoefficient = (value & DotNetReImpl.SMALL_COEFF_MASK64);
}
}
if (partsCoefficient == 0)
return Zero;
int exponent = partsExponent - DotNetReImpl.DECIMAL_EXPONENT_BIAS + n;
if (exponent >= 0) // value is already rounded
return value;
// All next - negative exponent case
BID_UINT64 divFactor;
int addExponent = 0;
{ // Truncate all digits except last one
int absPower = -exponent;
if (absPower >= MaxFormatDigits)
{
divFactor = MaxCoefficient + 1;
int expShift = MaxFormatDigits;
addExponent = absPower - expShift;
}
else
{
divFactor = PowersOfTen[absPower];
}
}
// Process last digit
switch (roundType)
{
case RoundingMode.Up:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
break;
case RoundingMode.Down:
partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
break;
case RoundingMode.Ceiling:
if (partsSignMask == 0/*!parts.isNegative()*/)
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
else
partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
break;
case RoundingMode.Floor:
if (partsSignMask == 0/*!parts.isNegative()*/)
partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
else
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
break;
case RoundingMode.HalfUp:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2) / divFactor) * divFactor : 0;
break;
case RoundingMode.HalfDown:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1) / divFactor) * divFactor : 0;
break;
case RoundingMode.HalfEven:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1 + ((partsCoefficient / divFactor) & 1L)) / divFactor) * divFactor : 0;
break;
case RoundingMode.Unnecessary:
if (addExponent != 0 /*&& partsCoefficient != 0 - always true: checked earlier*/ || partsCoefficient % divFactor != 0)
throw new ArithmeticException("Rounding necessary");
return value;
default:
throw new ArgumentException("Unsupported roundType(=" + roundType + ") value.");
}
partsExponent += addExponent;
if (partsCoefficient == 0)
return Zero;
BID_UINT32 fpsf = DotNetReImpl.BID_EXACT_STATUS;
return DotNetReImpl.get_BID64(partsSignMask, partsExponent, partsCoefficient, DotNetReImpl.BID_ROUNDING_TO_NEAREST, ref fpsf);
}