in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImpl.java [2230:2349]
public static long round(final long value, final int n, final RoundingMode roundType) {
if (isNonFinite(value))
return value;
if (n > JavaImpl.MAX_EXPONENT)
return value;
if (n < JavaImpl.MIN_EXPONENT)
return JavaImpl.ZERO;
// final Decimal64Parts parts = tlsDecimal64Parts.get();
// JavaImpl.toParts(value, parts);
long partsCoefficient;
long partsSignMask;
int partsExponent;
{ // Copy-paste the toParts method for speedup
partsSignMask = value & MASK_SIGN;
if (isSpecial(value)) {
// if (isNonFinite(value)) {
// partsExponent = 0;
//
// partsCoefficient = value & 0xFE03_FFFF_FFFF_FFFFL;
// if ((value & 0x0003_FFFF_FFFF_FFFFL) > MAX_COEFFICIENT)
// partsCoefficient = value & ~MASK_COEFFICIENT;
// if (isInfinity(value))
// partsCoefficient = value & MASK_SIGN_INFINITY_NAN; // TODO: Why this was done??
// } else
{
// Check for non-canonical values.
final long coefficient = (value & LARGE_COEFFICIENT_MASK) | LARGE_COEFFICIENT_HIGH_BIT;
partsCoefficient = coefficient > MAX_COEFFICIENT ? 0 : coefficient;
// Extract exponent.
final long tmp = value >> EXPONENT_SHIFT_LARGE;
partsExponent = (int) (tmp & EXPONENT_MASK);
}
} else {
// Extract exponent. Maximum biased value for "small exponent" is 0x2FF(*2=0x5FE), signed: []
// upper 1/4 of the mask range is "special", as checked in the code above
final long tmp = value >> EXPONENT_SHIFT_SMALL;
partsExponent = (int) (tmp & EXPONENT_MASK);
// Extract coefficient.
partsCoefficient = (value & SMALL_COEFFICIENT_MASK);
}
}
if (partsCoefficient == 0)
return Decimal64Utils.ZERO;
final int exponent = partsExponent - JavaImpl.EXPONENT_BIAS + n;
if (exponent >= 0) // value is already rounded
return value;
// All next - negative exponent case
final long divFactor;
int addExponent = 0;
{ // Truncate all digits except last one
int absPower = -exponent;
if (absPower >= MAX_FORMAT_DIGITS) {
divFactor = MAX_COEFFICIENT + 1;
final int expShift = MAX_FORMAT_DIGITS;
addExponent = absPower - expShift;
} else {
divFactor = POWERS_OF_TEN[absPower];
}
}
// Process last digit
switch (roundType) {
case UP:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
break;
case DOWN:
partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
break;
case 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 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 HALF_UP:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2) / divFactor) * divFactor : 0;
break;
case HALF_DOWN:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1) / divFactor) * divFactor : 0;
break;
case HALF_EVEN:
partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1 + ((partsCoefficient / divFactor) & 1L)) / divFactor) * divFactor : 0;
break;
case UNNECESSARY:
if (!isRoundedImpl(addExponent, partsCoefficient, divFactor))
throw new ArithmeticException("Rounding necessary");
return value;
default:
throw new IllegalArgumentException("Unsupported roundType(=" + roundType + ") value.");
}
partsExponent += addExponent;
if (partsCoefficient == 0)
return JavaImpl.ZERO;
return pack(partsSignMask, partsExponent, partsCoefficient, BID_ROUNDING_TO_NEAREST); // JavaImpl.fromParts(parts)
}