static long __bid_full_round64()

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