in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplParse.java [733:872]
public static long get_BID64_UF(final long sgn, final int expon, long coeff, final long R, int rmode, final FloatingPointStatusFlag fpsc) {
long C128_w0, C128_w1, Q_low_w0, Q_low_w1, Stemp_w0, Stemp_w1;
long _C64, remainder_h, QH, carry;
int extra_digits, amount, amount2;
int status;
// underflow
if (expon + MAX_FORMAT_DIGITS < 0) {
__set_status_flags(fpsc, BID_UNDERFLOW_EXCEPTION | BID_INEXACT_EXCEPTION);
if (rmode == BID_ROUNDING_DOWN && sgn != 0)
return 0x8000000000000001L;
if (rmode == BID_ROUNDING_UP && sgn == 0)
return 1L;
// result is 0
return sgn;
}
// 10*coeff
coeff = (coeff << 3) + (coeff << 1);
if (sgn != 0 && (rmode == BID_ROUNDING_DOWN || rmode == BID_ROUNDING_UP) /*(uint)(rmode - 1) < 2*/)
rmode = 3 - rmode;
if (R != 0)
coeff |= 1;
// get digits to be shifted out
extra_digits = 1 - expon;
C128_w0 = coeff + bid_round_const_table[rmode][extra_digits];
// get coeff*(2^M[extra_digits])/10^extra_digits
//__mul_64x128_full(out QH, out Q_low, C128.w0, 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 _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(C128_w0, _B_w1);
_ALBH_w0 = C128_w0 * _B_w1;
//__mul_64x64_to_128(out ALBL, A, B.w0);
_ALBL_w1 = Mul64Impl.unsignedMultiplyHigh(C128_w0, _B_w0);
_ALBL_w0 = C128_w0 * _B_w0;
Q_low_w0 = _ALBL_w0;
//__add_128_64(out QM2, ALBH, ALBL.w1);
{
long R64H;
R64H = _ALBH_w1;
_QM2_w0 = (_ALBL_w1) + _ALBH_w0;
if ((UnsignedLong.isLess(_QM2_w0, _ALBL_w1)))
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;
//__shr_128(C128, Q_high, amount);
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 & 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--;
}
}
if (is_inexact(fpsc))
__set_status_flags(fpsc, BID_UNDERFLOW_EXCEPTION);
else {
status = BID_INEXACT_EXCEPTION;
// get remainder
remainder_h = QH << (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
long CY;
//__add_carry_out(out Stemp_w0, out CY, Q_low_w0, bid_reciprocals10_128_flat[(extra_digits << 1) + 0]);
{
final long __Y = bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) /*+ 0*/];
Stemp_w0 = Q_low_w0 + __Y;
CY = (UnsignedLong.isLess(Stemp_w0, Q_low_w0)) ? 1L : 0;
}
//__add_carry_in_out(out Stemp_w1, out carry, Q_low_w1, bid_reciprocals10_128_flat[(extra_digits << 1) + 1], CY);
{
final long __Y = bid_reciprocals10_128_BID_UINT128[(extra_digits << 1) + 1];
final long __X1;
__X1 = Q_low_w1 + CY;
Stemp_w1 = __X1 + __Y;
carry = ((UnsignedLong.isLess(Stemp_w1, __X1)) || (UnsignedLong.isLess(__X1, CY))) ? 1L : 0;
}
if ((UnsignedLong.isGreaterOrEqual((remainder_h >>> (64 - amount)) + carry, 1L << amount)))
status = BID_EXACT_STATUS;
break;
}
if (status != BID_EXACT_STATUS)
__set_status_flags(fpsc, BID_UNDERFLOW_EXCEPTION | status);
}
return sgn | _C64;
}