public static long bid64_from_int64()

in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplCast.java [522:712]


    public static long bid64_from_int64(final long /*BID_SINT64*/ x, final int rnd_mode/*, final JavaImplParse.FloatingPointStatusFlag pfpsf*/) {
        long /*BID_UINT64*/ res;
        long /*BID_UINT64*/ x_sign, C;
        /*unsigned*/
        int q, ind;
        int incr_exp = 0;
        int is_midpoint_lt_even = 0, is_midpoint_gt_even = 0;
        int is_inexact_lt_midpoint = 0, is_inexact_gt_midpoint = 0;

        x_sign = x & 0x8000000000000000L;
        // if the integer is negative, use the absolute value
        if (x_sign != 0)
            C = ~x + 1;
        else
            C = x;
        if (UnsignedLong.isLessOrEqual(C, BID64_SIG_MAX)) {    // |C| <= 10^16-1 and the result is exact
            if (UnsignedLong.isLess(C, 0x0020000000000000L)) {    // C < 2^53
                res = x_sign | 0x31c0000000000000L | C;
            } else {    // C >= 2^53
                res = x_sign | 0x6c70000000000000L | (C & 0x0007ffffffffffffL);
            }
        } else {    // |C| >= 10^16 and the result may be inexact
            // the smallest |C| is 10^16 which has 17 decimal digits
            // the largest |C| is 0x8000000000000000 = 9223372036854775808 w/ 19 digits
            if (UnsignedLong.isLess(C, 0x16345785d8a0000L)) {    // x < 10^17
                q = 17;
                ind = 1;    // number of digits to remove for q = 17
            } else if (UnsignedLong.isLess(C, 0xde0b6b3a7640000L)) {    // C < 10^18
                q = 18;
                ind = 2;    // number of digits to remove for q = 18
            } else {    // C < 10^19
                q = 19;
                ind = 3;    // number of digits to remove for q = 19
            }
            // overflow and underflow are not possible
            // Note: performance can be improved by inlining this call


            //bid_round64_2_18(    // will work for 19 digits too if C fits in 64 bits
            //    q, ind, C, &res, &incr_exp,
            //    &is_midpoint_lt_even, &is_midpoint_gt_even, &is_inexact_lt_midpoint, &is_inexact_gt_midpoint);
            {

                long /*BID_UINT128*/ __P128_w0, __P128_w1;
                long /*BID_UINT128*/ __fstar_w0, __fstar_w1;
                long /*BID_UINT64*/ __Cstar;
                long /*BID_UINT64*/ __tmp64;
                int __shift;
                int __ind;

                // Note:
                //    In round128_2_18() positive numbers with 2 <= q <= 18 will be
                //    rounded to nearest only for 1 <= __x <= 3:
                //     __x = 1 or __x = 2 when q = 17
                //     __x = 2 or __x = 3 when q = 18
                // However, for generality and possible uses outside the frame of IEEE 754
                // this implementation works for 1 <= __x <= q - 1

                // assume *is_midpoint_lt_even, *is_midpoint_gt_even,
                // *is_inexact_lt_midpoint, and *is_inexact_gt_midpoint are
                // initialized to 0 by the caller

                // round a number C with q decimal digits, 2 <= q <= 18
                // to q - __x digits, 1 <= __x <= 17
                // C = C + 1/2 * 10^__x where the result C fits in 64 bits
                // (because the largest value is 999999999999999999 + 50000000000000000 =
                // 0x0e92596fd628ffff, which fits in 60 bits)
                __ind = ind - 1;    // 0 <= __ind <= 16
                C = C + bid_midpoint64[__ind];
                // kx ~= 10^(-__x), kx = bid_Kx64[__ind] * 2^(-Ex), 0 <= __ind <= 16
                // __P128 = (C + 1/2 * 10^__x) * kx * 2^Ex = (C + 1/2 * 10^__x) * Kx
                // the approximation kx of 10^(-__x) was rounded up to 64 bits

                //__mul_64x64_to_128MACH(__P128, C, bid_Kx64[__ind]);
                {
                    final long __CY = bid_Kx64[__ind];
                    __P128_w1 = Mul64Impl.unsignedMultiplyHigh(C, __CY);
                    __P128_w0 = C * __CY;
                }

                // calculate C* = floor (__P128) and f*
                // __Cstar = __P128 >> Ex
                // __fstar = low Ex bits of __P128
                __shift = bid_Ex64m64[__ind];    // in [3, 56]
                __Cstar = __P128_w1 >>> __shift;
                __fstar_w1 = __P128_w1 & bid_mask64[__ind];
                __fstar_w0 = __P128_w0;
                // the top Ex bits of 10^(-__x) are T* = bid_ten2mxtrunc64[__ind], e.g.
                // if __x=1, T*=bid_ten2mxtrunc64[0]=0xcccccccccccccccc
                // if (0 < f* < 10^(-__x)) then the result is a midpoint
                //   if floor(C*) is even then C* = floor(C*) - logical right
                //       __shift; C* has q - __x decimal digits, correct by Prop. 1)
                //   else if floor(C*) is odd C* = floor(C*)-1 (logical right
                //       __shift; C* has q - __x decimal digits, correct by Pr. 1)
                // else
                //   C* = floor(C*) (logical right __shift; C has q - __x decimal digits,
                //       correct by Property 1)
                // in the caling function n = C* * 10^(e+__x)

                // determine inexactness of the rounding of C*
                // if (0 < f* - 1/2 < 10^(-__x)) then
                //   the result is exact
                // else // if (f* - 1/2 > T*) then
                //   the result is inexact
                if (UnsignedLong.isGreater(__fstar_w1, bid_half64[__ind]) ||
                    (__fstar_w1 == bid_half64[__ind] && __fstar_w0 != 0)) {
                    // f* > 1/2 and the result may be exact
                    // Calculate f* - 1/2
                    __tmp64 = __fstar_w1 - bid_half64[__ind];
                    if (__tmp64 != 0 || UnsignedLong.isGreater(__fstar_w0, bid_ten2mxtrunc64[__ind])) {    // f* - 1/2 > 10^(-__x)
                        is_inexact_lt_midpoint = 1;
                    }    // else the result is exact
                } else {    // the result is inexact; f2* <= 1/2
                    is_inexact_gt_midpoint = 1;
                }
                // check for midpoints (could do this before determining inexactness)
                if (__fstar_w1 == 0 && UnsignedLong.isLessOrEqual(__fstar_w0, bid_ten2mxtrunc64[__ind])) {
                    // the result is a midpoint
                    if ((__Cstar & 0x01) != 0) {    // __Cstar is odd; MP in [EVEN, ODD]
                        // if floor(C*) is odd C = floor(C*) - 1; the result may be 0
                        __Cstar--;    // __Cstar is now even
                        is_midpoint_gt_even = 1;
                        is_inexact_lt_midpoint = 0;
                        is_inexact_gt_midpoint = 0;
                    } else {    // else MP in [ODD, EVEN]
                        is_midpoint_lt_even = 1;
                        is_inexact_lt_midpoint = 0;
                        is_inexact_gt_midpoint = 0;
                    }
                }
                // check for rounding overflow, which occurs if __Cstar = 10^(q-__x)
                __ind = q - ind;    // 1 <= __ind <= q - 1
                if (__Cstar == bid_ten2k64[__ind]) {    // if  __Cstar = 10^(q-__x)
                    __Cstar = bid_ten2k64[__ind - 1];    // __Cstar = 10^(q-__x-1)
                    incr_exp = 1;
                } else {    // 10^33 <= __Cstar <= 10^34 - 1
                    incr_exp = 0;
                }
                res = __Cstar;
            }


            if (incr_exp != 0)
                ind++;
            // set the inexact flag
//            if (is_inexact_lt_midpoint!=0 || is_inexact_gt_midpoint!=0 ||
//                is_midpoint_lt_even!=0 || is_midpoint_gt_even!=0)
//                __set_status_flags(pfpsf, BID_INEXACT_EXCEPTION);
            // general correction from RN to RA, RM, RP, RZ; result uses ind for exp
            if (rnd_mode != BID_ROUNDING_TO_NEAREST) {
                if ((x_sign == 0
                    && ((rnd_mode == BID_ROUNDING_UP && is_inexact_lt_midpoint != 0)
                    ||
                    ((rnd_mode == BID_ROUNDING_TIES_AWAY
                        || rnd_mode == BID_ROUNDING_UP) && is_midpoint_gt_even != 0)))
                    || (x_sign != 0
                    && ((rnd_mode == BID_ROUNDING_DOWN && is_inexact_lt_midpoint != 0)
                    ||
                    ((rnd_mode == BID_ROUNDING_TIES_AWAY
                        || rnd_mode == BID_ROUNDING_DOWN)
                        && is_midpoint_gt_even != 0)))) {
                    res = res + 1;
                    if (res == 0x002386f26fc10000L) {    // res = 10^16 => rounding overflow
                        res = 0x00038d7ea4c68000L;    // 10^15
                        ind = ind + 1;
                    }
                } else if ((is_midpoint_lt_even != 0 || is_inexact_gt_midpoint != 0) &&
                    ((x_sign != 0 && (rnd_mode == BID_ROUNDING_UP ||
                        rnd_mode == BID_ROUNDING_TO_ZERO)) ||
                        (x_sign == 0 && (rnd_mode == BID_ROUNDING_DOWN ||
                            rnd_mode == BID_ROUNDING_TO_ZERO)))) {
                    res = res - 1;
                    // check if we crossed into the lower decade
                    if (res == 0x00038d7ea4c67fffL) {    // 10^15 - 1
                        res = 0x002386f26fc0ffffL;    // 10^16 - 1
                        ind = ind - 1;
                    }
                } else {
                    ;    // exact, the result is already correct
                }
            }
            if (UnsignedLong.isLess(res, 0x0020000000000000L)) {    // res < 2^53
                res = x_sign | (((long) ind + 398) << 53) | res;
            } else {    // res >= 2^53
                res =
                    x_sign | 0x6000000000000000L | (((long) ind + 398) << 51) |
                        (res & 0x0007ffffffffffffL);
            }
        }
        return res;
    }