in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImpl.java [2004:2210]
public static long pack(final long signMask, final int exponentIn, final long coefficientIn, int roundingMode) {
final long Q_low_0;
final long Q_low_1;
final long QH;
long r;
long mask;
long _C64;
long remainder_h;
int exponent = exponentIn;
long coefficient = coefficientIn;
final int extra_digits;
final int amount;
final int amount2;
// TODO: optimize: (coefficient always positive! & use more efficient comparison)
long tenDivRem = 0;
boolean isAnyNonZeroRem = false;
while (UnsignedLong.isGreater(coefficient, 9999999999999999L)) {
tenDivRem = coefficient % 10;
if (tenDivRem != 0) {
if (roundingMode == BID_ROUNDING_EXCEPTION)
throwPackException(signMask, exponentIn, coefficientIn);
isAnyNonZeroRem = true;
}
coefficient /= 10;
exponent++;
}
if (isAnyNonZeroRem) {
switch (roundingMode) {
case BID_ROUNDING_TO_NEAREST:
if (tenDivRem >= 5) // Rounding away from zero
coefficient++;
break;
case BID_ROUNDING_DOWN:
if (signMask != 0 /*&& isAnyNonZeroRem - already checked*/)
coefficient++;
break;
case BID_ROUNDING_UP:
if (signMask == 0 /*&& isAnyNonZeroRem - already checked*/)
coefficient++;
break;
case BID_ROUNDING_TO_ZERO:
break;
case BID_ROUNDING_TIES_AWAY:
//if (isAnyNonZeroRem) - already checked
coefficient++;
break;
case BID_ROUNDING_EXCEPTION:
throwPackException(signMask, exponentIn, coefficientIn);
default:
throw new IllegalArgumentException("Unsupported roundingMode(=" + roundingMode + ") value.");
}
}
if (UnsignedLong.isGreater(coefficient, 9999999999999999L)) {
if (roundingMode == BID_ROUNDING_EXCEPTION)
throwPackException(signMask, exponentIn, coefficientIn);
exponent++;
coefficient = 1000000000000000L;
}
// Check for possible underflow/overflow.
if (exponent > BIASED_EXPONENT_MAX_VALUE || exponent < 0) {
if (exponent < 0) {
// Underflow.
if (exponent + MAX_FORMAT_DIGITS < 0) {
if (roundingMode == BID_ROUNDING_EXCEPTION)
throwPackException(signMask, exponentIn, coefficientIn);
if (roundingMode == BID_ROUNDING_DOWN && signMask < 0)
return 0x8000000000000001L;
if (roundingMode == BID_ROUNDING_UP && signMask >= 0)
return 1L;
return signMask;
}
if (signMask < 0 && (roundingMode == BID_ROUNDING_DOWN || roundingMode == BID_ROUNDING_UP))
roundingMode = 3 - roundingMode;
// Get digits to be shifted out
extra_digits = -exponent;
coefficient += bid_round_const_table[roundingMode][extra_digits];
// Get coefficient * (2^M[extra_digits])/10^extra_digits
{
final long ALBL_0;
final long ALBL_1;
final long ALBH_0;
final long ALBH_1;
final long QM2_0;
final long QM2_1;
{
final long __CY = bid_reciprocals10_128[extra_digits][1];
ALBH_1 = Mul64Impl.unsignedMultiplyHigh(coefficient, __CY);
ALBH_0 = coefficient * __CY;
}
{
final long __CY = bid_reciprocals10_128[extra_digits][0];
ALBL_1 = Mul64Impl.unsignedMultiplyHigh(coefficient, __CY);
ALBL_0 = coefficient * __CY;
}
Q_low_0 = ALBL_0;
{
long R64H;
R64H = ALBH_1;
QM2_0 = ALBL_1 + ALBH_0;
if (QM2_0 < ALBL_1)
R64H++;
QM2_1 = R64H;
}
Q_low_1 = QM2_0;
QH = QM2_1;
}
// Now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
amount = bid_recip_scale[extra_digits];
_C64 = QH >>> amount;
if (roundingMode == BID_ROUNDING_TO_NEAREST)
if ((_C64 & 1) != 0) {
// Check whether fractional part of initial_P/10^extra_digits is exactly .5
// Get remainder
amount2 = 64 - amount;
remainder_h = 0;
remainder_h--;
remainder_h >>>= amount2;
remainder_h = remainder_h & QH;
if (remainder_h == 0L
&& (Q_low_1 < bid_reciprocals10_128[extra_digits][1]
|| (Q_low_1 == bid_reciprocals10_128[extra_digits][1]
&& Q_low_0 < bid_reciprocals10_128[extra_digits][0]))) {
_C64--;
}
}
return signMask | _C64;
}
if (coefficient == 0L) {
if (exponent > BIASED_EXPONENT_MAX_VALUE)
exponent = BIASED_EXPONENT_MAX_VALUE;
}
while (UnsignedLong.isLess(coefficient, 1000000000000000L) && exponent >= 3 * 256) {
exponent--;
coefficient = (coefficient << 3) + (coefficient << 1);
}
if (exponent > BIASED_EXPONENT_MAX_VALUE) {
// Overflow
r = signMask | MASK_INFINITY_AND_NAN;
switch (roundingMode) {
case BID_ROUNDING_EXCEPTION:
throwPackException(signMask, exponentIn, coefficientIn);
case BID_ROUNDING_DOWN:
if (signMask >= 0)
r = MAX_VALUE;
break;
case BID_ROUNDING_TO_ZERO:
r = signMask | MAX_VALUE;
break;
case BID_ROUNDING_UP:
if (signMask < 0)
r = MIN_VALUE;
}
return r;
}
}
mask = 1L << EXPONENT_SHIFT_SMALL;
// Check whether coefficient fits in 10 * 5 + 3 bits.
if (coefficient < mask) {
r = exponent;
r <<= EXPONENT_SHIFT_SMALL;
return r | coefficient | signMask;
}
// Special format.
// Eliminate the case coefficient == 10^16 after rounding.
if (coefficient == 10000000000000000L) {
r = exponent + 1L; // TODO: optimize, including the line above!
r <<= EXPONENT_SHIFT_SMALL;
return r | 1000000000000000L | signMask;
}
r = exponent;
r <<= EXPONENT_SHIFT_LARGE;
r |= (signMask | MASK_SPECIAL);
// Add coefficient, without leading bits.
mask = (mask >>> 2) - 1;
coefficient &= mask;
r |= coefficient;
return r;
}