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