in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplMul.java [664:788]
public static long get_BID64(long sgn, int expon, long coeff) {
long Q_low_w0, Q_low_w1;
long QH, r, mask, _C64, remainder_h, carry;
int extra_digits, amount, amount2;
if ((UnsignedLong.isGreater(coeff, 9999999999999999L))) {
expon++;
coeff = 1000000000000000L;
}
// check for possible underflow/overflow
if ((/*UnsignedInteger.compare*/(expon) + Integer.MIN_VALUE >= (3 * 256) + Integer.MIN_VALUE)) {
if (expon < 0) {
// underflow
if (expon + MAX_FORMAT_DIGITS < 0) {
// result is 0
return sgn;
}
// get digits to be shifted out
extra_digits = -expon;
coeff += bid_round_const_table_nearest[extra_digits];
// get coeff*(2^M[extra_digits])/10^extra_digits
//__mul_64x128_full(out QH, out Q_low, coeff, bid_reciprocals10_128_flat[extra_digits << 1], bid_reciprocals10_128_flat[(extra_digits << 1) + 1]);
//public static void __mul_64x128_full(/*out*/ long Ph, /*out*/ final BID_UINT128 Ql, final long A, final long B_w0, final long B_w1)
{
final long _A = coeff;
final long _B_w0 = bid_reciprocals10_128_BID_UINT128[extra_digits << 1];
final long _B_w1 = bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1];
long _ALBL_w0, _ALBL_w1, _ALBH_w0, _ALBH_w1, _QM2_w0, _QM2_w1;
//__mul_64x64_to_128(out ALBH, A, B.w1);
_ALBH_w1 = Mul64Impl.unsignedMultiplyHigh(_A, _B_w1);
_ALBH_w0 = _A * _B_w1;
//__mul_64x64_to_128(out ALBL, A, B.w0);
_ALBL_w1 = Mul64Impl.unsignedMultiplyHigh(_A, _B_w0);
_ALBL_w0 = _A * _B_w0;
Q_low_w0 = _ALBL_w0;
//__add_128_64(out QM2, ALBH, ALBL.w1);
{
final long __A128_w0 = _ALBH_w0;
final long __A128_w1 = _ALBH_w1;
final long __B64 = _ALBL_w1;
long R64H;
R64H = __A128_w1;
_QM2_w0 = (__B64) + __A128_w0;
if ((UnsignedLong.isLess(_QM2_w0, __B64)))
R64H++;
_QM2_w1 = R64H;
}
Q_low_w1 = _QM2_w0;
QH = _QM2_w1;
}
// 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 (BID_ROUNDING_TO_NEAREST == 0)*/ //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 == 0
&& ((UnsignedLong.isLess(Q_low_w1, bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1]))
|| (Q_low_w1 == bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1]
&& (UnsignedLong.isLess(Q_low_w0, bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 0]))))) {
_C64--;
}
}
return sgn | _C64;
}
if (coeff == 0) {
if (expon > DECIMAL_MAX_EXPON_64) expon = DECIMAL_MAX_EXPON_64;
}
while ((UnsignedLong.isLess(coeff, 1000000000000000L)) && expon >= 3 * 256) {
expon--;
coeff = (coeff << 3) + (coeff << 1);
}
if (expon > DECIMAL_MAX_EXPON_64) {
// overflow
return sgn | INFINITY_MASK64;
}
}
mask = 1;
mask <<= EXPONENT_SHIFT_SMALL64;
// check whether coefficient fits in 10*5+3 bits
if ((UnsignedLong.isLess(coeff, mask))) {
r = LONG_LOW_PART & expon;
r <<= EXPONENT_SHIFT_SMALL64;
r |= (coeff | sgn);
return r;
}
// special format
// eliminate the case coeff==10^16 after rounding
if (coeff == 10000000000000000L) {
r = LONG_LOW_PART & (expon + 1);
r <<= EXPONENT_SHIFT_SMALL64;
r |= (1000000000000000L | sgn);
return r;
}
r = LONG_LOW_PART & expon;
r <<= EXPONENT_SHIFT_LARGE64;
r |= (sgn | SPECIAL_ENCODING_MASK64);
// add coeff, without leading bits
mask = (mask >>> 2) - 1;
coeff &= mask;
r |= coeff;
return r;
}