static long bid_get_add128()

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*/);
        }
    }