in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplFma.java [1551:1974]
static long /*BID_UINT64*/ bid_get_add128(
long /*BID_UINT64*/ sign_x, int exponent_x, long /*BID_UINT64*/ coefficient_x,
long /*BID_UINT64*/ sign_y, int final_exponent_y, long /*BID_UINT128*/ CY_w0, long CY_w1,
int extra_digits/*, final int rounding_mode, FloatingPointStatusFlag fpsc*/) {
long /*BID_UINT128*/ CY_L_w0, CY_L_w1, CX_w0, CX_w1, FS_w0, FS_w1, F_w0, F_w1, CT_w0, CT_w1, ST_w0, ST_w1, T2_w0, T2_w1;
long /*BID_UINT64*/ CYh, CY0L, T, S, coefficient_y, remainder_y;
long /*BID_SINT64*/ D = 0;
long /*int_double*/ tempx_i;
int diff_dec_expon, extra_digits2, exponent_y;
// int status;
int extra_dx, diff_dec2, bin_expon_cx, digits_x, rmode;
int table_index;
final int rounding_mode = BID_ROUNDING_TO_NEAREST;
// CY has more than 16 decimal digits
exponent_y = final_exponent_y - extra_digits;
if (exponent_x > exponent_y) {
// normalize x
//--- get number of bits in the coefficients of x and y ---
tempx_i = UnsignedLong.longToDoubleRawBits(coefficient_x);
bin_expon_cx = (int) (((tempx_i & MASK_BINARY_EXPONENT) >>> 52) - 0x3ff);
// get number of decimal digits in the coeff_x
digits_x = bid_estimate_decimal_digits[bin_expon_cx];
if (UnsignedLong.isGreaterOrEqual(coefficient_x, bid_power10_table_128_BID_UINT128[(digits_x << 1) /*+ 0*/]))
digits_x++;
extra_dx = 16 - digits_x;
coefficient_x *= bid_power10_table_128_BID_UINT128[(extra_dx << 1) /*+ 0*/];
if ((sign_x ^ sign_y) != 0 && (coefficient_x == 1000000000000000L)) {
extra_dx++;
coefficient_x = 10000000000000000L;
}
exponent_x -= extra_dx;
if (exponent_x > exponent_y) {
// exponent_x > exponent_y
diff_dec_expon = exponent_x - exponent_y;
if (exponent_x <= final_exponent_y + 1) {
//__mul_64x64_to_128(CX, coefficient_x, bid_power10_table_128_flat[(diff_dec_expon << 1) /*+ 0*/]);
{
final long /*BID_UINT64*/ __CY = bid_power10_table_128_BID_UINT128[(diff_dec_expon << 1) /*+ 0*/];
CX_w1 = Mul64Impl.unsignedMultiplyHigh(coefficient_x, __CY);
CX_w0 = coefficient_x * __CY;
}
if (sign_x == sign_y) {
//__add_128_128(CT, CY, CX);
{
CT_w1 = CY_w1 + CX_w1;
CT_w0 = CX_w0 + CY_w0;
if ((UnsignedLong.isLess(CT_w0, CX_w0)))
CT_w1++;
}
if ((exponent_x > final_exponent_y) /*&& (final_exponent_y>0) */)
extra_digits++;
table_index = (16 + extra_digits) << 1;
if (__unsigned_compare_ge_128(CT_w0, CT_w1,
bid_power10_table_128_BID_UINT128[table_index],
bid_power10_table_128_BID_UINT128[table_index + 1]))
extra_digits++;
} else {
//__sub_128_128(CT, CY, CX);
{
CT_w1 = CY_w1 - CX_w1;
CT_w0 = CY_w0 - CX_w0;
if (UnsignedLong.isLess(CY_w0, CX_w0))
CT_w1--;
}
if ((/*(BID_SINT64)*/ CT_w1) < 0) {
CT_w0 = -CT_w0;
CT_w1 = -CT_w1;
if (CT_w0 != 0)
CT_w1--;
sign_y = sign_x;
} else if ((CT_w1 | CT_w0) == 0) {
sign_y = (rounding_mode != BID_ROUNDING_DOWN) ? 0 : 0x8000000000000000L;
}
if ((exponent_x + 1 >= final_exponent_y) /*&& (final_exponent_y>=0) */) {
extra_digits = __get_dec_digits64(CT_w0, CT_w1) - 16;
if (extra_digits <= 0) {
// if (CT_w0 == 0 && rounding_mode == BID_ROUNDING_DOWN)
// sign_y = 0x8000000000000000L;
return get_BID64(sign_y, exponent_y, CT_w0/*, rounding_mode, fpsc*/);
}
} else {
table_index = (15 + extra_digits) << 1;
if (__unsigned_compare_gt_128(bid_power10_table_128_BID_UINT128[table_index],
bid_power10_table_128_BID_UINT128[table_index + 1], CT_w0, CT_w1))
extra_digits--;
}
}
return __bid_full_round64(sign_y, exponent_y, CT_w0, CT_w1, extra_digits/*, rounding_mode, fpsc*/);
}
// diff_dec2+extra_digits is the number of digits to eliminate from
// argument CY
diff_dec2 = exponent_x - final_exponent_y;
if (diff_dec2 >= 17) {
// if (((rounding_mode) & 3) != 0) {
// switch (rounding_mode) {
// case BID_ROUNDING_UP:
// if (sign_y == 0) {
// D = (/*(BID_SINT64)*/ (sign_x ^ sign_y)) >> 63;
// D = D + D + 1;
// coefficient_x += D;
// }
// break;
// case BID_ROUNDING_DOWN:
// if (sign_y != 0) {
// D = (/*(BID_SINT64)*/ (sign_x ^ sign_y)) >> 63;
// D = D + D + 1;
// coefficient_x += D;
// }
// break;
// case BID_ROUNDING_TO_ZERO:
// if (sign_y != sign_x) {
// D = -1;
// coefficient_x += D;
// }
// break;
// }
// if (UnsignedLong.isLess(coefficient_x, 1000000000000000L)) {
// coefficient_x -= D;
// coefficient_x =
// D + (coefficient_x << 1) + (coefficient_x << 3);
// exponent_x--;
// }
// }
// if ((CY_w1 | CY_w0) != 0)
// __set_status_flags(fpsc, BID_INEXACT_EXCEPTION);
return get_BID64(sign_x, exponent_x, coefficient_x/*, rounding_mode, fpsc*/);
}
// here exponent_x <= 16+final_exponent_y
// truncate CY to 16 dec. digits
CYh = __truncate(CY_w0, CY_w1, extra_digits);
// get remainder
T = bid_power10_table_128_BID_UINT128[(extra_digits << 1) /*+ 0*/];
//__mul_64x64_to_64(CY0L, CYh, T);
CY0L = CYh * T;
remainder_y = CY_w0 - CY0L;
// align coeff_x, CYh
//__mul_64x64_to_128(CX, coefficient_x, bid_power10_table_128_flat[(diff_dec2 << 1) /*+ 0*/]);
{
long /*BID_UINT64*/ __CY = bid_power10_table_128_BID_UINT128[(diff_dec2 << 1) /*+ 0*/];
CX_w1 = Mul64Impl.unsignedMultiplyHigh(coefficient_x, __CY);
CX_w0 = coefficient_x * __CY;
}
if (sign_x == sign_y) {
//__add_128_64(CT, CX, CYh);
{
CT_w1 = CX_w1;
CT_w0 = CYh + CX_w0;
if (UnsignedLong.isLess(CT_w0, CYh))
CT_w1++;
}
table_index = (16 + diff_dec2) << 1;
if (__unsigned_compare_ge_128(CT_w0, CT_w1, bid_power10_table_128_BID_UINT128[table_index], bid_power10_table_128_BID_UINT128[table_index + 1]))
diff_dec2++;
} else {
if (remainder_y != 0)
CYh++;
//__sub_128_64(CT, CX, CYh);
{
CT_w1 = CX_w1;
CT_w0 = CX_w0 - CYh;
if (UnsignedLong.isLess(CX_w0, CYh))
CT_w1--;
}
table_index = (15 + diff_dec2) << 1;
if (__unsigned_compare_gt_128(bid_power10_table_128_BID_UINT128[table_index], bid_power10_table_128_BID_UINT128[table_index + 1], CT_w0, CT_w1))
diff_dec2--;
}
return __bid_full_round64_remainder(sign_x, final_exponent_y, CT_w0, CT_w1,
diff_dec2, remainder_y/*, rounding_mode, fpsc, 0*/);
}
}
// Here (exponent_x <= exponent_y)
{
diff_dec_expon = exponent_y - exponent_x;
if (diff_dec_expon > MAX_FORMAT_DIGITS) {
rmode = rounding_mode;
if ((sign_x ^ sign_y) != 0) {
if (CY_w0 == 0)
CY_w1--;
CY_w0--;
table_index = (15 + extra_digits) << 1;
if (__unsigned_compare_gt_128(bid_power10_table_128_BID_UINT128[table_index],
bid_power10_table_128_BID_UINT128[table_index + 1], CY_w0, CY_w1)) {
if ((rmode & 3) != 0) {
extra_digits--;
final_exponent_y--;
} else {
CY_w0 = 1000000000000000L;
CY_w1 = 0;
extra_digits = 0;
}
}
}
//__scale128_10(CY, CY);
{
long /*BID_UINT128*/ _TMP2_w0, _TMP2_w1, _TMP8_w0, _TMP8_w1;
_TMP2_w1 = (CY_w1 << 1) | (CY_w0 >>> 63);
_TMP2_w0 = CY_w0 << 1;
_TMP8_w1 = (CY_w1 << 3) | (CY_w0 >>> 61);
_TMP8_w0 = CY_w0 << 3;
//__add_128_128(CY, _TMP2, _TMP8);
{
CY_w1 = _TMP2_w1 + _TMP8_w1;
CY_w0 = _TMP8_w0 + _TMP2_w0;
if (UnsignedLong.isLess(CY_w0, _TMP8_w0))
CY_w1++;
}
}
extra_digits++;
CY_w0 |= 1;
return __bid_simple_round64_sticky(sign_y, final_exponent_y, CY_w0, CY_w1, extra_digits/*, rmode, fpsc*/);
}
// apply sign to coeff_x
sign_x ^= sign_y;
sign_x = (/*(BID_SINT64)*/ sign_x) >> 63;
CX_w0 = (coefficient_x + sign_x) ^ sign_x;
CX_w1 = sign_x;
// check whether CY (rounded to 16 digits) and CX have
// any digits in the same position
diff_dec2 = final_exponent_y - exponent_x;
if (diff_dec2 <= 17) {
// align CY to 10^ex
S = bid_power10_table_128_BID_UINT128[(diff_dec_expon << 1) /*+ 0*/];
//__mul_64x128_short(CY_L, S, CY);
{
//__mul_64x64_to_64(ALBH_L, S, CY_w1);
final long /*BID_UINT64*/ ALBH_L = S * CY_w1;
//__mul_64x64_to_128(CY_L, S, CY_w0);
CY_L_w1 = Mul64Impl.unsignedMultiplyHigh(S, CY_w0);
CY_L_w0 = S * CY_w0;
CY_L_w1 += ALBH_L;
}
//__add_128_128(ST, CY_L, CX);
{
ST_w1 = CY_L_w1 + CX_w1;
ST_w0 = CX_w0 + CY_L_w0;
if ((UnsignedLong.isLess(ST_w0, CX_w0)))
ST_w1++;
}
extra_digits2 = __get_dec_digits64(ST_w0, ST_w1) - 16;
return __bid_full_round64(sign_y, exponent_x, ST_w0, ST_w1, extra_digits2/*, rounding_mode, fpsc*/);
}
// truncate CY to 16 dec. digits
CYh = __truncate(CY_w0, CY_w1, extra_digits);
// get remainder
T = bid_power10_table_128_BID_UINT128[(extra_digits << 1) /*+ 0*/];
//__mul_64x64_to_64(CY0L, CYh, T);
CY0L = CYh * T;
coefficient_y = CY_w0 - CY0L;
// add rounding constant
rmode = rounding_mode;
// if (sign_y != 0 && (rmode == BID_ROUNDING_DOWN || rmode == BID_ROUNDING_UP) /*(uint)(rmode - 1) < 2*/)
// rmode = 3 - rmode;
// if ((rmode & 3) == 0) //BID_ROUNDING_TO_NEAREST
{
coefficient_y += bid_round_const_table[rmode][extra_digits];
}
// align coefficient_y, coefficient_x
S = bid_power10_table_128_BID_UINT128[(diff_dec_expon << 1) /*+ 0*/];
//__mul_64x64_to_128(F, coefficient_y, S);
{
F_w1 = Mul64Impl.unsignedMultiplyHigh(coefficient_y, S);
F_w0 = coefficient_y * S;
}
// fraction
//__add_128_128(FS, F, CX);
{
FS_w1 = F_w1 + CX_w1;
FS_w0 = CX_w0 + F_w0;
if ((UnsignedLong.isLess(FS_w0, CX_w0)))
FS_w1++;
}
// if (rmode == 0) //BID_ROUNDING_TO_NEAREST
{
// rounding code, here RN_EVEN
// 10^(extra_digits+diff_dec_expon)
table_index = (diff_dec_expon + extra_digits) << 1;
T2_w0 = bid_power10_table_128_BID_UINT128[table_index];
T2_w1 = bid_power10_table_128_BID_UINT128[table_index + 1];
if (__unsigned_compare_gt_128(FS_w0, FS_w1, T2_w0, T2_w1)
|| ((CYh & 1) != 0 && (FS_w1 == T2_w1 && FS_w0 == T2_w0) /*__test_equal_128(FS, T2)*/)) {
CYh++;
//__sub_128_128(FS, FS, T2);
{
long /*BID_UINT128*/ Q128_w1 = FS_w1 - T2_w1;
long /*BID_UINT128*/ Q128_w0 = FS_w0 - T2_w0;
if (UnsignedLong.isLess(FS_w0, T2_w0))
Q128_w1--;
FS_w1 = Q128_w1;
FS_w0 = Q128_w0;
}
}
}
// if (rmode == 4) //BID_ROUNDING_TO_NEAREST
// {
// // rounding code, here RN_AWAY
// // 10^(extra_digits+diff_dec_expon)
// table_index = (diff_dec_expon + extra_digits) << 1;
// T2_w0 = bid_power10_table_128_BID_UINT128[table_index];
// T2_w1 = bid_power10_table_128_BID_UINT128[table_index + 1];
// if (__unsigned_compare_ge_128(FS_w0, FS_w1, T2_w0, T2_w1)) {
// CYh++;
// //__sub_128_128(FS, FS, T2);
// {
// long /*BID_UINT128*/ Q128_w1 = FS_w1 - T2_w1;
// long /*BID_UINT128*/ Q128_w0 = FS_w0 - T2_w0;
// if (UnsignedLong.isLess(FS_w0, T2_w0))
// Q128_w1--;
// FS_w1 = Q128_w1;
// FS_w0 = Q128_w0;
// }
// }
// }
// switch (rmode) {
// case BID_ROUNDING_DOWN:
// case BID_ROUNDING_TO_ZERO:
// if (/*(BID_SINT64)*/ FS_w1 < 0) {
// CYh--;
// if (UnsignedLong.isLess(CYh, 1000000000000000L)) {
// CYh = 9999999999999999L;
// final_exponent_y--;
// }
// } else {
// table_index = (diff_dec_expon + extra_digits) << 1;
// T2_w0 = bid_power10_table_128_BID_UINT128[table_index];
// T2_w1 = bid_power10_table_128_BID_UINT128[table_index + 1];
// if (__unsigned_compare_ge_128(FS_w0, FS_w1, T2_w0, T2_w1)) {
// CYh++;
// //__sub_128_128(FS, FS, T2);
// {
// long /*BID_UINT128*/ Q128_w1 = FS_w1 - T2_w1;
// long /*BID_UINT128*/ Q128_w0 = FS_w0 - T2_w0;
// if (UnsignedLong.isLess(FS_w0, T2_w0))
// Q128_w1--;
// FS_w1 = Q128_w1;
// FS_w0 = Q128_w0;
// }
// }
// }
// break;
// case BID_ROUNDING_UP:
// if (/*(BID_SINT64)*/ FS_w1 < 0)
// break;
// table_index = (diff_dec_expon + extra_digits) << 1;
// T2_w0 = bid_power10_table_128_BID_UINT128[table_index];
// T2_w1 = bid_power10_table_128_BID_UINT128[table_index + 1];
// if (__unsigned_compare_gt_128(FS_w0, FS_w1, T2_w0, T2_w1)) {
// CYh += 2;
// //__sub_128_128(FS, FS, T2);
// {
// long /*BID_UINT128*/ Q128_w1 = FS_w1 - T2_w1;
// long /*BID_UINT128*/ Q128_w0 = FS_w0 - T2_w0;
// if (UnsignedLong.isLess(FS_w0, T2_w0))
// Q128_w1--;
// FS_w1 = Q128_w1;
// FS_w0 = Q128_w0;
// }
// } else if ((FS_w1 == T2_w1) && (FS_w0 == T2_w0)) {
// CYh++;
// FS_w1 = FS_w0 = 0;
// } else if ((FS_w1 | FS_w0) != 0)
// CYh++;
// break;
// }
// status = BID_INEXACT_EXCEPTION;
// if ((rmode & 3) == 0) {
// // RN modes
// table_index = (diff_dec_expon + extra_digits) << 1;
// if ((FS_w1 == bid_round_const_table_128_BID_UINT128[0][table_index + 1])
// && (FS_w0 == bid_round_const_table_128_BID_UINT128[0][table_index /*+ 0*/]))
// status = BID_EXACT_STATUS;
// } else if (FS_w1 == 0 && FS_w0 == 0)
// status = BID_EXACT_STATUS;
// __set_status_flags(fpsc, status);
return get_BID64(sign_y, final_exponent_y, CYh/*, rounding_mode, fpsc*/);
}
}