public static BID_UINT64 get_BID64()

in csharp/EPAM.Deltix.DFP/DotNetReImpl.cs [1109:1340]


		public static BID_UINT64 get_BID64(BID_UINT64 sgn, int exponIn, BID_UINT64 coeffIn, int rmode, ref uint fpsc)
		{
			BID_UINT128 Stemp, Q_low;
			BID_UINT64 QH, r, mask, _C64, remainder_h, CY, carry;
			int extra_digits, amount, amount2;
			uint status;

			int expon = exponIn;
			BID_UINT64 coeff = coeffIn;

			BID_UINT64 tenDivRem = 0;
			bool isAnyNonZeroRem = false;
			while (coeff > 9999999999999999UL)
			{
				tenDivRem = coeff % 10;
				if (tenDivRem != 0)
				{
					if (rmode == BID_ROUNDING_EXCEPTION)
						ThrowPackException(sgn, exponIn, coeffIn);
					isAnyNonZeroRem = true;
				}
				coeff /= 10;
				expon++;
			}

			if (isAnyNonZeroRem)
			{
				switch (rmode)
				{
					case BID_ROUNDING_TO_NEAREST:
						if (tenDivRem >= 5) // Rounding away from zero
							coeff++;
						break;

					case BID_ROUNDING_DOWN:
						if (sgn != 0 /*&& isAnyNonZeroRem - already checked*/)
							coeff++;
						break;

					case BID_ROUNDING_UP:
						if (sgn == 0 /*&& isAnyNonZeroRem - already checked*/)
							coeff++;
						break;

					case BID_ROUNDING_TO_ZERO:
						break;

					case BID_ROUNDING_TIES_AWAY:
						//if (isAnyNonZeroRem)  - already checked
						coeff++;
						break;

					case BID_ROUNDING_EXCEPTION:
						ThrowPackException(sgn, exponIn, coeffIn);
						break;

					default:
						throw new ArgumentException("Unsupported roundingMode(=" + rmode + ") value.");

				}
			}

			if (coeff > 9999999999999999UL)
			{
				if (rmode == BID_ROUNDING_EXCEPTION)
					ThrowPackException(sgn, exponIn, coeffIn);
				expon++;
				coeff = 1000000000000000UL;
			}
			// check for possible underflow/overflow
			if (((uint)expon) >= 3 * 256)
			{
				if (expon < 0)
				{
					// underflow
					if (expon + MAX_FORMAT_DIGITS < 0)
					{
						__set_status_flags(ref fpsc, BID_UNDERFLOW_EXCEPTION | BID_INEXACT_EXCEPTION);
						if (rmode == BID_ROUNDING_EXCEPTION)
							ThrowPackException(sgn, exponIn, coeffIn);
						if (rmode == BID_ROUNDING_DOWN && sgn != 0)
							return 0x8000000000000001UL;
						if (rmode == BID_ROUNDING_UP && sgn == 0)
							return 1UL;
						// result is 0
						return sgn;
					}
					if (sgn != 0 && (uint)(rmode - 1) < 2)
						rmode = 3 - rmode;
					// get digits to be shifted out
					extra_digits = -expon;
					coeff += bid_round_const_table[rmode, extra_digits];

					// get coeff*(2^M[extra_digits])/10^extra_digits
					__mul_64x128_full(out QH, out Q_low, coeff, bid_reciprocals10_128[extra_digits]);

					// now get P/10^extra_digits: shift Q_high right by M[extra_digits]-128
					amount = bid_recip_scale[extra_digits];

					_C64 = QH >> amount;

					if (rmode == 0) //BID_ROUNDING_TO_NEAREST
						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 == 0
								&& (Q_low.w1 < bid_reciprocals10_128[extra_digits].w1
								|| (Q_low.w1 == bid_reciprocals10_128[extra_digits].w1
									&& Q_low.w0 < bid_reciprocals10_128[extra_digits].w0)))
							{
								_C64--;
							}
						}


					if (is_inexact(fpsc))
						__set_status_flags(ref fpsc, BID_UNDERFLOW_EXCEPTION);
					else
					{
						status = BID_INEXACT_EXCEPTION;
						// get remainder
						remainder_h = QH << (64 - amount);

						switch (rmode)
						{
							case BID_ROUNDING_TO_NEAREST:
							case BID_ROUNDING_TIES_AWAY:
								// test whether fractional part is 0
								if (remainder_h == 0x8000000000000000UL
									&& (Q_low.w1 < bid_reciprocals10_128[extra_digits].w1
									|| (Q_low.w1 == bid_reciprocals10_128[extra_digits].w1
										&& Q_low.w0 < bid_reciprocals10_128[extra_digits].w0)))
									status = BID_EXACT_STATUS;
								break;
							case BID_ROUNDING_DOWN:
							case BID_ROUNDING_TO_ZERO:
								if (remainder_h == 0
									&& (Q_low.w1 < bid_reciprocals10_128[extra_digits].w1
									|| (Q_low.w1 == bid_reciprocals10_128[extra_digits].w1
										&& Q_low.w0 < bid_reciprocals10_128[extra_digits].w0)))
									status = BID_EXACT_STATUS;
								break;
							default:
								// round up
								__add_carry_out(out Stemp.w0, out CY, Q_low.w0, bid_reciprocals10_128[extra_digits].w0);
								__add_carry_in_out(out Stemp.w1, out carry, Q_low.w1, bid_reciprocals10_128[extra_digits].w1, CY);
								if ((remainder_h >> (64 - amount)) + carry >= (((BID_UINT64)1) << amount))
									status = BID_EXACT_STATUS;
								break;
						}

						if (status != BID_EXACT_STATUS)
							__set_status_flags(ref fpsc, BID_UNDERFLOW_EXCEPTION | status);
					}


					return sgn | _C64;
				}
				if (coeff == 0) { if (expon > DECIMAL_MAX_EXPON_64) expon = DECIMAL_MAX_EXPON_64; }
				while (coeff < 1000000000000000UL && expon >= 3 * 256)
				{
					expon--;
					coeff = (coeff << 3) + (coeff << 1);
				}
				if (expon > DECIMAL_MAX_EXPON_64)
				{
					__set_status_flags(ref fpsc, BID_OVERFLOW_EXCEPTION | BID_INEXACT_EXCEPTION);
					// overflow
					r = sgn | INFINITY_MASK64;
					switch (rmode)
					{
						case BID_ROUNDING_EXCEPTION:
							ThrowPackException(sgn, exponIn, coeffIn);
							break;

						case BID_ROUNDING_DOWN:
							if (sgn == 0)
								r = LARGEST_BID64;
							break;
						case BID_ROUNDING_TO_ZERO:
							r = sgn | LARGEST_BID64;
							break;
						case BID_ROUNDING_UP:
							// round up
							if (sgn != 0)
								r = SMALLEST_BID64;
							break;
					}
					return r;
				}
			}

			mask = 1;
			mask <<= EXPONENT_SHIFT_SMALL64;

			// check whether coefficient fits in 10*5+3 bits
			if (coeff < mask)
			{
				r = (BID_UINT64)expon;
				r <<= EXPONENT_SHIFT_SMALL64;
				r |= (coeff | sgn);
				return r;
			}
			// special format

			// eliminate the case coeff==10^16 after rounding
			if (coeff == 10000000000000000UL)
			{
				r = (BID_UINT64)(expon + 1);
				r <<= EXPONENT_SHIFT_SMALL64;
				r |= (1000000000000000UL | sgn);
				return r;
			}

			r = (BID_UINT64)expon;
			r <<= EXPONENT_SHIFT_LARGE64;
			r |= (sgn | SPECIAL_ENCODING_MASK64);
			// add coeff, without leading bits
			mask = (mask >> 2) - 1;
			coeff &= mask;
			r |= coeff;

			return r;
		}