public static long pack()

in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImpl.java [2004:2210]


    public static long pack(final long signMask, final int exponentIn, final long coefficientIn, int roundingMode) {
        final long Q_low_0;
        final long Q_low_1;
        final long QH;
        long r;
        long mask;
        long _C64;
        long remainder_h;

        int exponent = exponentIn;
        long coefficient = coefficientIn;

        final int extra_digits;
        final int amount;
        final int amount2;

        // TODO: optimize: (coefficient always positive! & use more efficient comparison)
        long tenDivRem = 0;
        boolean isAnyNonZeroRem = false;
        while (UnsignedLong.isGreater(coefficient, 9999999999999999L)) {
            tenDivRem = coefficient % 10;
            if (tenDivRem != 0) {
                if (roundingMode == BID_ROUNDING_EXCEPTION)
                    throwPackException(signMask, exponentIn, coefficientIn);
                isAnyNonZeroRem = true;
            }
            coefficient /= 10;
            exponent++;
        }

        if (isAnyNonZeroRem) {
            switch (roundingMode) {
                case BID_ROUNDING_TO_NEAREST:
                    if (tenDivRem >= 5) // Rounding away from zero
                        coefficient++;
                    break;

                case BID_ROUNDING_DOWN:
                    if (signMask != 0 /*&& isAnyNonZeroRem - already checked*/)
                        coefficient++;
                    break;

                case BID_ROUNDING_UP:
                    if (signMask == 0 /*&& isAnyNonZeroRem - already checked*/)
                        coefficient++;
                    break;

                case BID_ROUNDING_TO_ZERO:
                    break;

                case BID_ROUNDING_TIES_AWAY:
                    //if (isAnyNonZeroRem)  - already checked
                    coefficient++;
                    break;

                case BID_ROUNDING_EXCEPTION:
                    throwPackException(signMask, exponentIn, coefficientIn);

                default:
                    throw new IllegalArgumentException("Unsupported roundingMode(=" + roundingMode + ") value.");

            }
        }

        if (UnsignedLong.isGreater(coefficient, 9999999999999999L)) {
            if (roundingMode == BID_ROUNDING_EXCEPTION)
                throwPackException(signMask, exponentIn, coefficientIn);
            exponent++;
            coefficient = 1000000000000000L;
        }

        // Check for possible underflow/overflow.
        if (exponent > BIASED_EXPONENT_MAX_VALUE || exponent < 0) {
            if (exponent < 0) {
                // Underflow.
                if (exponent + MAX_FORMAT_DIGITS < 0) {
                    if (roundingMode == BID_ROUNDING_EXCEPTION)
                        throwPackException(signMask, exponentIn, coefficientIn);
                    if (roundingMode == BID_ROUNDING_DOWN && signMask < 0)
                        return 0x8000000000000001L;
                    if (roundingMode == BID_ROUNDING_UP && signMask >= 0)
                        return 1L;
                    return signMask;
                }

                if (signMask < 0 && (roundingMode == BID_ROUNDING_DOWN || roundingMode == BID_ROUNDING_UP))
                    roundingMode = 3 - roundingMode;

                // Get digits to be shifted out
                extra_digits = -exponent;
                coefficient += bid_round_const_table[roundingMode][extra_digits];

                // Get coefficient * (2^M[extra_digits])/10^extra_digits
                {
                    final long ALBL_0;
                    final long ALBL_1;
                    final long ALBH_0;
                    final long ALBH_1;
                    final long QM2_0;
                    final long QM2_1;
                    {
                        final long __CY = bid_reciprocals10_128[extra_digits][1];
                        ALBH_1 = Mul64Impl.unsignedMultiplyHigh(coefficient, __CY);
                        ALBH_0 = coefficient * __CY;
                    }
                    {
                        final long __CY = bid_reciprocals10_128[extra_digits][0];
                        ALBL_1 = Mul64Impl.unsignedMultiplyHigh(coefficient, __CY);
                        ALBL_0 = coefficient * __CY;
                    }
                    Q_low_0 = ALBL_0;
                    {
                        long R64H;
                        R64H = ALBH_1;
                        QM2_0 = ALBL_1 + ALBH_0;
                        if (QM2_0 < ALBL_1)
                            R64H++;
                        QM2_1 = R64H;
                    }
                    Q_low_1 = QM2_0;
                    QH = QM2_1;
                }

                // Now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
                amount = bid_recip_scale[extra_digits];

                _C64 = QH >>> amount;

                if (roundingMode == 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 == 0L
                            && (Q_low_1 < bid_reciprocals10_128[extra_digits][1]
                            || (Q_low_1 == bid_reciprocals10_128[extra_digits][1]
                            && Q_low_0 < bid_reciprocals10_128[extra_digits][0]))) {
                            _C64--;
                        }
                    }
                return signMask | _C64;
            }
            if (coefficient == 0L) {
                if (exponent > BIASED_EXPONENT_MAX_VALUE)
                    exponent = BIASED_EXPONENT_MAX_VALUE;
            }
            while (UnsignedLong.isLess(coefficient, 1000000000000000L) && exponent >= 3 * 256) {
                exponent--;
                coefficient = (coefficient << 3) + (coefficient << 1);
            }
            if (exponent > BIASED_EXPONENT_MAX_VALUE) {
                // Overflow
                r = signMask | MASK_INFINITY_AND_NAN;
                switch (roundingMode) {
                    case BID_ROUNDING_EXCEPTION:
                        throwPackException(signMask, exponentIn, coefficientIn);

                    case BID_ROUNDING_DOWN:
                        if (signMask >= 0)
                            r = MAX_VALUE;
                        break;

                    case BID_ROUNDING_TO_ZERO:
                        r = signMask | MAX_VALUE;
                        break;

                    case BID_ROUNDING_UP:
                        if (signMask < 0)
                            r = MIN_VALUE;
                }
                return r;
            }
        }

        mask = 1L << EXPONENT_SHIFT_SMALL;

        // Check whether coefficient fits in 10 * 5 + 3 bits.
        if (coefficient < mask) {
            r = exponent;
            r <<= EXPONENT_SHIFT_SMALL;
            return r | coefficient | signMask;
        }
        // Special format.

        // Eliminate the case coefficient == 10^16 after rounding.
        if (coefficient == 10000000000000000L) {
            r = exponent + 1L; // TODO: optimize, including the line above!
            r <<= EXPONENT_SHIFT_SMALL;
            return r | 1000000000000000L | signMask;
        }

        r = exponent;
        r <<= EXPONENT_SHIFT_LARGE;
        r |= (signMask | MASK_SPECIAL);

        // Add coefficient, without leading bits.
        mask = (mask >>> 2) - 1;
        coefficient &= mask;
        r |= coefficient;

        return r;
    }