public static long bid64_to_int64_xint()

in java/dfp/src/main/java/com/epam/deltix/dfp/JavaImplCast.java [10:224]


    public static long /*BID_SINT64*/ bid64_to_int64_xint(final long /*BID_UINT64*/ x /*, final JavaImplParse.FloatingPointStatusFlag pfpsf*/) {
        long /*BID_SINT64*/ res;
        long /*BID_UINT64*/ x_sign;
        long /*BID_UINT64*/ x_exp;
        int exp;            // unbiased exponent
        // Note: C1 represents x_significand (BID_UINT64)
        //BID_UI64DOUBLE tmp1;
        /*unsigned*/
        int x_nr_bits;
        int q, ind, shift;
        long /*BID_UINT64*/ C1;
        long /*BID_UINT128*/ C_w0, C_w1;
        long /*BID_UINT64*/ Cstar;            // C* represents up to 16 decimal digits ~ 54 bits
//        long /*BID_UINT128*/ fstar_w0, fstar_w1;                                            //@XINT
        long /*BID_UINT128*/ P128_w0, P128_w1;

        // check for NaN or Infinity
        if ((x & MASK_NAN) == MASK_NAN || (x & MASK_INF) == MASK_INF) {
            // set invalid flag
//            __set_status_flags(pfpsf, BID_INVALID_EXCEPTION);
            // return Integer Indefinite
            return 0x8000000000000000L;
        }
        // unpack x
        x_sign = x & MASK_SIGN;    // 0 for positive, MASK_SIGN for negative
        // if steering bits are 11 (condition will be 0), then exponent is G[0:w+1] =>
        if ((x & MASK_STEERING_BITS) == MASK_STEERING_BITS) {
            x_exp = (x & MASK_BINARY_EXPONENT2) >>> 51;    // biased
            C1 = (x & MASK_BINARY_SIG2) | MASK_BINARY_OR2;
            if (C1 > 9999999999999999L) {    // non-canonical
                x_exp = 0;
                C1 = 0;
            }
        } else {
            x_exp = (x & MASK_BINARY_EXPONENT1) >>> 53;    // biased
            C1 = x & MASK_BINARY_SIG1;
        }

        // check for zeros (possibly from non-canonical values)
        if (C1 == 0x0L) {
            // x is 0
            return 0x00000000;
        }
        // x is not special and is not zero

        // q = nr. of decimal digits in x (1 <= q <= 54)
        //  determine first the nr. of bits in x
        if (UnsignedLong.isGreaterOrEqual(C1, 0x0020000000000000L)) {    // x >= 2^53
            // split the 64-bit value in two 32-bit halves to avoid rounding errors
            final long tmp1_ui64 = Double.doubleToRawLongBits((double) (C1 >>> 32));    // exact conversion

            x_nr_bits = 33 + ((((/*unsigned*/ int) (tmp1_ui64 >>> 52)) & 0x7ff) - 0x3ff);
        } else {    // if x < 2^53
            final long tmp1_ui64 = Double.doubleToRawLongBits((double) C1);    // exact conversion
            x_nr_bits = 1 + ((((/*unsigned*/ int) (tmp1_ui64 >>> 52)) & 0x7ff) - 0x3ff);
        }
        q = (int) bid_nr_digits_flat[((x_nr_bits - 1) << 2) /*+ 0 .digits*/];
        if (q == 0) {
            q = (int) bid_nr_digits_flat[((x_nr_bits - 1) << 2) + 3 /*.digits1*/];
            if (UnsignedLong.isGreaterOrEqual(C1, bid_nr_digits_flat[((x_nr_bits - 1) << 2) + 2/*.threshold_lo*/]))
                q++;
        }
        exp = (int) (x_exp - 398);    // unbiased exponent

        if ((q + exp) > 19) {    // x >= 10^19 ~= 2^63.11... (cannot fit in BID_SINT64)
            // set invalid flag
//            __set_status_flags(pfpsf, BID_INVALID_EXCEPTION);
            // return Integer Indefinite
            return 0x8000000000000000L;
        } else if ((q + exp) == 19) {    // x = c(0)c(1)...c(18).c(19)...c(q-1)
            // in this case 2^63.11... ~= 10^19 <= x < 10^20 ~= 2^66.43...
            // so x rounded to an integer may or may not fit in a signed 64-bit int
            // the cases that do not fit are identified here; the ones that fit
            // fall through and will be handled with other cases further,
            // under '1 <= q + exp <= 19'
            if (x_sign != 0) {    // if n < 0 and q + exp = 19
                // if n <= -2^63 - 1 then n is too large
                // too large if c(0)c(1)...c(18).c(19)...c(q-1) >= 2^63+1
                // <=> 0.c(0)c(1)...c(q-1) * 10^20 >= 5*(2^64+2), 1<=q<=16
                // <=> 0.c(0)c(1)...c(q-1) * 10^20 >= 0x5000000000000000a, 1<=q<=16
                // <=> C * 10^(20-q) >= 0x5000000000000000a, 1<=q<=16
                // 1 <= q <= 16 => 4 <= 20-q <= 19 => 10^(20-q) is 64-bit, and so is C1

                //__mul_64x64_to_128MACH(C, C1, bid_ten2k64[20 - q]);
                {
                    final long __CY = bid_ten2k64[20 - q];
                    C_w1 = Mul64Impl.unsignedMultiplyHigh(C1, __CY);
                    C_w0 = C1 * __CY;
                }

                // Note: C1 * 10^(11-q) has 19 or 20 digits; 0x5000000000000000a, has 20
                if (UnsignedLong.isGreater(C_w1, 0x05L) || (C_w1 == 0x05L && UnsignedLong.isGreaterOrEqual(C_w0, 0x0aL))) {
                    // set invalid flag
//                    __set_status_flags(pfpsf, BID_INVALID_EXCEPTION);
                    // return Integer Indefinite
                    return 0x8000000000000000L;
                }
                // else cases that can be rounded to a 64-bit int fall through
                // to '1 <= q + exp <= 19'
            } else {    // if n > 0 and q + exp = 19
                // if n >= 2^63 then n is too large
                // too large if c(0)c(1)...c(18).c(19)...c(q-1) >= 2^63
                // <=> if 0.c(0)c(1)...c(q-1) * 10^20 >= 5*2^64, 1<=q<=16
                // <=> if 0.c(0)c(1)...c(q-1) * 10^20 >= 0x50000000000000000, 1<=q<=16
                // <=> if C * 10^(20-q) >= 0x50000000000000000, 1<=q<=16
                C_w1 = 0x0000000000000005L;
                C_w0 = 0x0000000000000000L;
                // 1 <= q <= 16 => 4 <= 20-q <= 19 => 10^(20-q) is 64-bit, and so is C1

                //__mul_64x64_to_128MACH(C, C1, bid_ten2k64[20 - q]);
                {
                    final long __CY = bid_ten2k64[20 - q];
                    C_w1 = Mul64Impl.unsignedMultiplyHigh(C1, __CY);
                    C_w0 = C1 * __CY;
                }

                if (UnsignedLong.isGreaterOrEqual(C_w1, 0x05L)) {
                    // actually C.w[1] == 0x05ull && C.w[0] >= 0x0000000000000000ull) {
                    // set invalid flag
//                    __set_status_flags(pfpsf, BID_INVALID_EXCEPTION);
                    // return Integer Indefinite
                    return 0x8000000000000000L;
                }
                // else cases that can be rounded to a 64-bit int fall through
                // to '1 <= q + exp <= 19'
            }    // end else if n > 0 and q + exp = 19
        }    // end else if ((q + exp) == 19)

        // n is not too large to be converted to int64: -2^63-1 < n < 2^63
        // Note: some of the cases tested for above fall through to this point
        if ((q + exp) <= 0) {    // n = +/-0.0...c(0)c(1)...c(q-1)
            // set inexact flag                                                             //@XINT
//            __set_status_flags(pfpsf, BID_INEXACT_EXCEPTION);                               //@XINT
            // return 0
            return 0x0000000000000000L;
        } else {    // if (1 <= q + exp <= 19, 1 <= q <= 16, -15 <= exp <= 18)
            // -2^63-1 < x <= -1 or 1 <= x < 2^63 so x can be rounded
            // to nearest to a 64-bit signed integer
            if (exp < 0) {    // 2 <= q <= 16, -15 <= exp <= -1, 1 <= q + exp <= 19
                ind = -exp;    // 1 <= ind <= 15; ind is a synonym for 'x'
                // chop off ind digits from the lower part of C1
                // C1 fits in 64 bits
                // calculate C* and f*
                // C* is actually floor(C*) in this case
                // C* and f* need shifting and masking, as shown by
                // bid_shiftright128[] and bid_maskhigh128[]
                // 1 <= x <= 15
                // kx = 10^(-x) = bid_ten2mk64[ind - 1]
                // C* = C1 * 10^(-x)
                // the approximation of 10^(-x) was rounded up to 54 bits

                //__mul_64x64_to_128MACH(P128, C1, bid_ten2mk64[ind - 1]);
                {
                    final long __CY = bid_ten2mk64[ind - 1];
                    P128_w1 = Mul64Impl.unsignedMultiplyHigh(C1, __CY);
                    P128_w0 = C1 * __CY;
                }

                Cstar = P128_w1;
//                fstar_w1 = P128_w1 & bid_maskhigh128[ind - 1];                              //@XINT
//                fstar_w0 = P128_w0;                                                         //@XINT
                // the top Ex bits of 10^(-x) are T* = bid_ten2mk128trunc[ind].w[0], e.g.
                // if x=1, T*=bid_ten2mk128trunc[0].w[0]=0x1999999999999999
                // C* = floor(C*) (logical right shift; C has p decimal digits,
                //     correct by Property 1)
                // n = C* * 10^(e+x)

                // shift right C* by Ex-64 = bid_shiftright128[ind]
                shift = bid_shiftright128[ind - 1];    // 0 <= shift <= 39
                Cstar = Cstar >>> shift;

                // determine inexactness of the rounding of C*                              //@XINT
                // if (0 < f* < 10^(-x)) then                                               //@XINT
                //   the result is exact                                                    //@XINT
                // else // if (f* > T*) then                                                //@XINT
                //   the result is inexact                                                  //@XINT
//                if (ind - 1 <= 2) {    // fstar.w[1] is 0                                   //@XINT
//                    if (UnsignedLong.isGreater(fstar_w0, bid_ten2mk128trunc_flat[((ind - 1) << 1) + 1])) { //@XINT
//                        // bid_ten2mk128trunc[ind -1].w[1] is identical to                  //@XINT
//                        // bid_ten2mk128[ind -1].w[1]                                       //@XINT
//                        // set the inexact flag                                             //@XINT
//                        __set_status_flags(pfpsf, BID_INEXACT_EXCEPTION);                   //@XINT
//                    }    // else the result is exact                                        //@XINT
//                } else {    // if 3 <= ind - 1 <= 14                                        //@XINT
//                    if (fstar_w1 != 0 || UnsignedLong.isGreater(fstar_w0, bid_ten2mk128trunc_flat[((ind - 1) << 1) + 1])) { //@XINT
//                        // bid_ten2mk128trunc[ind -1].w[1] is identical to                  //@XINT
//                        // bid_ten2mk128[ind -1].w[1]                                       //@XINT
//                        // set the inexact flag                                             //@XINT
//                        __set_status_flags(pfpsf, BID_INEXACT_EXCEPTION);                   //@XINT
//                    }    // else the result is exact                                        //@XINT
//                }                                                                           //@XINT

                if (x_sign != 0)
                    res = -Cstar;
                else
                    res = Cstar;
            } else if (exp == 0) {
                // 1 <= q <= 16
                // res = +/-C (exact)
                if (x_sign != 0)
                    res = -C1;
                else
                    res = C1;
            } else {    // if (exp > 0) => 1 <= exp <= 18, 1 <= q <= 16, 2 <= q + exp <= 20
                // (the upper limit of 20 on q + exp is due to the fact that
                // +/-C * 10^exp is guaranteed to fit in 64 bits)
                // res = +/-C * 10^exp (exact)
                if (x_sign != 0)
                    res = -C1 * bid_ten2k64[exp];
                else
                    res = C1 * bid_ten2k64[exp];
            }
        }
        return res;
    }