in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplFma.java [1183:1369]
static long /*BID_UINT64*/ __bid_full_round64(
long /*BID_UINT64*/ sign, int exponent, long /*BID_UINT128*/ P_w0, long P_w1,
int extra_digits /*, int rounding_mode, FloatingPointStatusFlag fpsc*/) {
long /*BID_UINT128*/ Q_high_w0, Q_high_w1, Q_low_w0, Q_low_w1, C128_w0, C128_w1, Stemp_w0, Stemp_w1;
long /*BID_UINT64*/ remainder_h, C64, carry, CY;
int amount, amount2, rmode;
// int status = 0;
if (exponent < 0) {
if (exponent >= -16 && (extra_digits + exponent < 0)) {
extra_digits = -exponent;
// status = BID_UNDERFLOW_EXCEPTION;
}
}
if (extra_digits > 0) {
exponent += extra_digits;
rmode = BID_ROUNDING_TO_NEAREST; // rounding_mode;
// if (sign != 0 && (rmode == BID_ROUNDING_DOWN || rmode == BID_ROUNDING_UP) /*(uint)(rmode - 1) < 2*/)
// rmode = 3 - rmode;
//__add_128_128(P, P, bid_round_const_table_128[rmode][extra_digits]);
{
long /*BID_UINT128*/ B128_w0 = bid_round_const_table_128_BID_UINT128[rmode][(extra_digits << 1) /*+ 0*/];
long /*BID_UINT128*/ B128_w1 = bid_round_const_table_128_BID_UINT128[rmode][(extra_digits << 1) + 1];
long /*BID_UINT128*/ Q128_w1 = P_w1 + B128_w1;
long /*BID_UINT128*/ Q128_w0 = B128_w0 + P_w0;
if (UnsignedLong.isLess(Q128_w0, B128_w0))
Q128_w1++;
P_w1 = Q128_w1;
P_w0 = Q128_w0;
}
// get P*(2^M[extra_digits])/10^extra_digits
//__mul_128x128_full(Q_high, Q_low, P, bid_reciprocals10_128[extra_digits]);
{
final long _A_w0 = P_w0;
final long _A_w1 = P_w1;
final long _B_w0 = bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) /*+ 0*/];
final long _B_w1 = bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1];
long _ALBL_w0, _ALBH_w0, _AHBL_w0, _AHBH_w0, _QM_w0, _QM2_w0;
long _ALBL_w1, _ALBH_w1, _AHBL_w1, _AHBH_w1, _QM_w1, _QM2_w1;
//__mul_64x64_to_128(ALBH, (A)_w0, (B)_w1);
_ALBH_w1 = Mul64Impl.unsignedMultiplyHigh(_A_w0, _B_w1);
_ALBH_w0 = _A_w0 * _B_w1;
//__mul_64x64_to_128(AHBL, (B)_w0, (A)_w1);
_AHBL_w1 = Mul64Impl.unsignedMultiplyHigh(_B_w0, _A_w1);
_AHBL_w0 = _B_w0 * _A_w1;
//__mul_64x64_to_128(ALBL, (A)_w0, (B)_w0);
_ALBL_w1 = Mul64Impl.unsignedMultiplyHigh(_A_w0, _B_w0);
_ALBL_w0 = _A_w0 * _B_w0;
//__mul_64x64_to_128(AHBH, (A)_w1,(B)_w1);
_AHBH_w1 = Mul64Impl.unsignedMultiplyHigh(_A_w1, _B_w1);
_AHBH_w0 = _A_w1 * _B_w1;
//__add_128_128(QM, ALBH, AHBL); // add 128-bit value to 128-bit assume no carry-out
{
long Q128_w0, Q128_w1;
Q128_w1 = _ALBH_w1 + _AHBL_w1;
Q128_w0 = _AHBL_w0 + _ALBH_w0;
if ((UnsignedLong.isLess(Q128_w0, _AHBL_w0)))
Q128_w1++;
_QM_w1 = Q128_w1;
_QM_w0 = Q128_w0;
}
Q_low_w0 = _ALBL_w0;
//__add_128_64(_QM2, QM, ALBL_w1); // add 64-bit value to 128-bit
{
long __R64H;
__R64H = _QM_w1;
_QM2_w0 = _ALBL_w1 + _QM_w0;
if ((UnsignedLong.isLess(_QM2_w0, _ALBL_w1)))
__R64H++;
_QM2_w1 = __R64H;
}
//__add_128_64((_Qh), AHBH, QM2_w1); // add 64-bit value to 128-bit
{
long __R64H;
__R64H = _AHBH_w1;
Q_high_w0 = _QM2_w1 + _AHBH_w0;
if ((UnsignedLong.isLess(Q_high_w0, _QM2_w1)))
__R64H++;
Q_high_w1 = __R64H;
}
Q_low_w1 = _QM2_w0;
}
// now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
amount = bid_recip_scale[extra_digits];
//__shr_128_long(C128, Q_high, amount);
{
if (amount < 64) {
C128_w0 = Q_high_w0 >>> amount;
C128_w0 |= Q_high_w1 << (64 - amount);
C128_w1 = Q_high_w1 >>> amount;
} else {
C128_w0 = Q_high_w1 >>> ((amount) - 64);
C128_w1 = 0;
}
}
C64 = C128_w0;
// if (rmode == 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 & Q_high_w0;
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--;
}
}
// status |= BID_INEXACT_EXCEPTION;
// get remainder
remainder_h = Q_high_w0 << (64 - amount);
// switch (rmode) {
// case BID_ROUNDING_TO_NEAREST:
// case BID_ROUNDING_TIES_AWAY:
// // test whether fractional part is 0
// if (remainder_h == 0x8000000000000000L
// && (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*/]))))
// status = BID_EXACT_STATUS;
// break;
// case BID_ROUNDING_DOWN:
// case BID_ROUNDING_TO_ZERO:
// 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*/]))))
// status = BID_EXACT_STATUS;
// break;
// default:
// // round up
// //__add_carry_out(Stemp_w0, CY, Q_low_w0, bid_reciprocals10_128[extra_digits].w[0]);
// {
// Stemp_w0 = Q_low_w0 + bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) /*+ 0*/];
// CY = UnsignedLong.isLess(Stemp_w0, Q_low_w0) ? 1 : 0;
// }
//
// //__add_carry_in_out(Stemp_w1, carry, Q_low_w1, bid_reciprocals10_128[extra_digits].w[1], CY);
// {
// long /*BID_UINT64*/ X1 = Q_low_w1 + CY;
// Stemp_w1 = X1 + bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1];
// carry = (UnsignedLong.isLess(Stemp_w1, X1) || UnsignedLong.isLess(X1, CY)) ? 1 : 0;
// }
//
// if (UnsignedLong.isGreaterOrEqual((remainder_h >>> (64 - amount)) + carry, (((long /*BID_UINT64*/) 1) << amount)))
// status = BID_EXACT_STATUS;
// }
//
// __set_status_flags(fpsc, status);
} else {
C64 = P_w0;
if (C64 == 0) {
sign = 0;
// if (rounding_mode == BID_ROUNDING_DOWN)
// sign = 0x8000000000000000L;
}
}
return get_BID64(sign, exponent, C64/*, rounding_mode, fpsc*/);
}