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;
}