in csharp/EPAM.Deltix.DFP/DotNetImpl.cs [1949:2122]
public static UInt64 Pack(bool isNegative, Int32 exponent, UInt64 coefficient, Int32 roundingMode)
{
UInt64 sgn = isNegative ? SignMask : 0;
UInt64 Q_low_0, Q_low_1;
UInt64 QH, r, mask, _C64, remainder_h;
int extra_digits, amount, amount2;
if (coefficient > 9999999999999999UL)
{
exponent++;
coefficient = 1000000000000000UL;
}
// Check for possible underflow/overflow.
if (exponent > BiasedExponentMaxValue || exponent < 0)
{
if (exponent < 0)
{
// Underflow.
if (exponent + MaxFormatDigits < 0)
{
if (roundingMode == BidRoundingDown && isNegative)
return 0x8000000000000001UL;
if (roundingMode == BidRoundingUp && !isNegative)
return 1L;
return sgn;
}
if (isNegative && (roundingMode == BidRoundingDown || roundingMode == BidRoundingUp))
roundingMode = 3 - roundingMode;
// Get digits to be shifted out
extra_digits = -exponent;
coefficient += BidRoundConstTable[roundingMode, extra_digits];
// Get coefficient * (2^M[extra_digits])/10^extra_digits
{
ulong ALBL_0, ALBL_1, ALBH_0, ALBH_1, QM2_0, QM2_1;
{
ulong CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
CXH = coefficient >> 32;
CXL = (uint)((coefficient));
CYH = BidReciprocals10_128[extra_digits, 1] >> 32;
CYL = (uint)BidReciprocals10_128[extra_digits, 1];
PM = CXH * CYL;
PH = CXH * CYH;
PL = CXL * CYL;
PM2 = CXL * CYH;
PH += (PM >> 32);
PM = (PM & 0xFFFFFFFFL) + PM2 + (PL >> 32);
ALBH_1 = PH + (PM >> 32);
ALBH_0 = (PM << 32) + (uint)PL;
}
{
ulong CXH, CXL, CYH, CYL, PL, PH, PM, PM2;
CXH = ((coefficient)) >> 32;
CXL = (uint)((coefficient));
CYH = BidReciprocals10_128[extra_digits, 0] >> 32;
CYL = (uint)BidReciprocals10_128[extra_digits, 0];
PM = CXH * CYL;
PH = CXH * CYH;
PL = CXL * CYL;
PM2 = CXL * CYH;
PH += (PM >> 32);
PM = (PM & 0xFFFFFFFFL) + PM2 + (PL >> 32);
ALBL_1 = PH + (PM >> 32);
ALBL_0 = (PM << 32) + (PL & 0xFFFFFFFFL);
}
Q_low_0 = ALBL_0;
{
ulong 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 = BidRecipeScale[extra_digits];
_C64 = QH >> amount;
if (roundingMode == BidRoundingToNearest)
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 < BidReciprocals10_128[extra_digits, 1]
|| (Q_low_1 == BidReciprocals10_128[extra_digits, 1]
&& Q_low_0 < BidReciprocals10_128[extra_digits, 0])))
{
_C64--;
}
}
return sgn | _C64;
}
if (coefficient == 0L)
{
if (exponent > BiasedExponentMaxValue)
exponent = BiasedExponentMaxValue;
}
while (coefficient < 1000000000000000L && exponent >= 3 * 256)
{
exponent--;
coefficient = (coefficient << 3) + (coefficient << 1); // *= 10
}
if (exponent > BiasedExponentMaxValue)
{
// Overflow
r = sgn | InfinityMask;
if (roundingMode == BidRoundingDown)
{
if (!isNegative)
r = MaxValue;
}
else
if (roundingMode == BidRoundingToZero)
{
r = sgn | MaxValue;
}
else if (roundingMode == BidRoundingUp)
{
if (isNegative)
r = MinValue;
}
return r;
}
}
mask = 1;
mask <<= ExponentShiftSmall;
// Check whether coefficient fits in 10 * 5 + 3 bits.
if (coefficient < mask)
{
r = (ulong)exponent;
r <<= ExponentShiftSmall;
r |= (coefficient | sgn);
return r;
}
// Special format.
// Eliminate the case coefficient == 10^16 after rounding.
if (coefficient == 10000000000000000)
{
r = (ulong)(exponent + 1);
r <<= ExponentShiftSmall;
r |= (1000000000000000 | sgn);
return r;
}
r = (ulong)exponent;
r <<= ExponentShiftLarge;
r |= (sgn | SpecialEncodingMask);
// Add coefficient, without leading bits.
mask = (mask >> 2) - 1;
coefficient &= mask;
r |= coefficient;
return r;
}