public static UInt64 RoundToReciprocal()

in csharp/EPAM.Deltix.DFP/DotNetImpl.cs [690:1013]


		public static UInt64 RoundToReciprocal(UInt64 value, uint r, RoundingMode roundType)
		{
			if (r < 1)
				throw new ArgumentException("The r(=" + r + ") argument must be positive.");
			if (!IsFinite(value))
				return value;
			//if (Math.log10(r) > JavaImpl.MAX_EXPONENT) // Never can happens
			//	return value;
			//if (Math.log10(r) < JavaImpl.MIN_EXPONENT)
			//	return JavaImpl.ZERO;

			BID_UINT64 partsSignMask;
			int partsExponent;
			BID_UINT64 partsCoefficient;
			// DotNetReImpl.unpack_BID64(out partsSignMask, out partsExponent, out partsCoefficient, value);
			{ // Copy-paste the toParts method for speedup
				partsSignMask = value & 0x8000000000000000UL;

				if ((value & DotNetReImpl.SPECIAL_ENCODING_MASK64) == DotNetReImpl.SPECIAL_ENCODING_MASK64)
				{
					//if ((value & DotNetReImpl.INFINITY_MASK64) == DotNetReImpl.INFINITY_MASK64) - Non finite values are already checked
					//{
					//	partsExponent = 0;
					//	partsCoefficient = value & 0xfe03ffffffffffffUL;
					//	if ((value & 0x0003ffffffffffffUL) >= 1000000000000000UL)
					//		partsCoefficient = value & 0xfe00000000000000UL;
					//	if ((value & DotNetReImpl.NAN_MASK64) == DotNetReImpl.INFINITY_MASK64)
					//		partsCoefficient = value & DotNetReImpl.SINFINITY_MASK64;
					//	return 0;   // NaN or Infinity
					//} else
					{
						// Check for non-canonical values.
						BID_UINT64 coeff = (value & DotNetReImpl.LARGE_COEFF_MASK64) | DotNetReImpl.LARGE_COEFF_HIGH_BIT64;

						// check for non-canonical values
						if (coeff >= 10000000000000000UL)
							coeff = 0;
						partsCoefficient = coeff;
						// get exponent
						BID_UINT64 tmp = value >> DotNetReImpl.EXPONENT_SHIFT_LARGE64;
						partsExponent = (int)(tmp & DotNetReImpl.EXPONENT_MASK64);
					}
				}
				else
				{
					// exponent
					BID_UINT64 tmp = value >> DotNetReImpl.EXPONENT_SHIFT_SMALL64;
					partsExponent = (int)(tmp & DotNetReImpl.EXPONENT_MASK64);
					// coefficient
					partsCoefficient = (value & DotNetReImpl.SMALL_COEFF_MASK64);
				}
			}

			if (partsCoefficient == 0)
				return Zero;

			int unbiasedExponent = partsExponent - DotNetReImpl.DECIMAL_EXPONENT_BIAS;

			if (unbiasedExponent >= 0) // value is already rounded
				return value;

			// Denormalize partsCoefficient to the maximal value to get the maximal precision after final r division
			{
				int dn = NumberOfDigits(partsCoefficient);
				/*if (dn < PowersOfTen.Length - 1)*/
				{
					int expShift = (PowersOfTen.Length - 1) - dn;
					partsExponent -= expShift;
					unbiasedExponent -= expShift;
					partsCoefficient *= PowersOfTen[expShift];
				}
			}


			//Multiply partsCoefficient with r
			Pair96 coefficientMulR = new Pair96();
			{
				ulong l0 = (LONG_LOW_PART & partsCoefficient) * r;
				coefficientMulR.Set(LONG_LOW_PART & l0, (partsCoefficient >> 32) * r + (l0 >> 32));
			}

			//final long divFactor;
			Factors96 divFactor; // divFactor = divFactor1 * divFactor2 * divFactor3
			int addExponent;
			{
				int absPower = -unbiasedExponent;
				int maxPower = Math.Min(absPower, Math.Min(3 * 9, NumberOfDigits(coefficientMulR.w21) + 10 /* low part */));
				//divFactor = PowersOfTen[maxPower];
				int factor1Power = Math.Min(maxPower, 9); // Int can hold max 1_000_000_000
				divFactor.d01 = (uint)PowersOfTen[factor1Power];
				int factor2Power = Math.Min(maxPower - factor1Power, 9);
				divFactor.d02 = (uint)PowersOfTen[factor2Power];
				divFactor.d03 = (uint)PowersOfTen[maxPower - factor1Power - factor2Power];
				addExponent = absPower - maxPower;
			}

			// Process last digit
			switch (roundType)
			{
				case RoundingMode.Up:
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
					if (addExponent != 0)
					{
						coefficientMulR.Set(divFactor);

					}
					else
					{ // addExponent != 0
						{ // + divFactor - 1
							Pair96 divFactor96 = new Pair96();
							divFactor96.Set(divFactor);
							divFactor96.Add(new Pair96(0xFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL));
							coefficientMulR.Add(divFactor96);
						}
						coefficientMulR.Div(divFactor);
						coefficientMulR.Mul(divFactor);
					}
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
					break;

				case RoundingMode.Down:
					// partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
					if (addExponent != 0)
					{
						coefficientMulR.Set(0, 0);

					}
					else
					{ // addExponent != 0
						coefficientMulR.Div(divFactor);
						coefficientMulR.Mul(divFactor);
					}
					// partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
					break;

				case RoundingMode.Ceiling:
					if (partsSignMask >= 0/*!parts.isNegative()*/)
					{
						// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
						if (addExponent != 0)
						{
							coefficientMulR.Set(divFactor);

						}
						else
						{ // addExponent != 0
							{ // + divFactor - 1
								Pair96 divFactor96 = new Pair96();
								divFactor96.Set(divFactor);
								divFactor96.Add(new Pair96(0xFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL));
								coefficientMulR.Add(divFactor96);
							}
							coefficientMulR.Div(divFactor);
							coefficientMulR.Mul(divFactor);
						}
						// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;

					}
					else
					{ // partsSignMask >= 0
					  // partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
						if (addExponent != 0)
						{
							coefficientMulR.Set(0, 0);

						}
						else
						{ // addExponent != 0
							coefficientMulR.Div(divFactor);
							coefficientMulR.Mul(divFactor);
						}
						// partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
					}
					break;

				case RoundingMode.Floor:
					if (partsSignMask >= 0/*!parts.isNegative()*/)
					{
						// partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;
						if (addExponent != 0)
						{
							coefficientMulR.Set(0, 0);

						}
						else
						{ // addExponent != 0
							coefficientMulR.Div(divFactor);
							coefficientMulR.Mul(divFactor);
						}
						// partsCoefficient = addExponent == 0 ? (partsCoefficient / divFactor) * divFactor : 0;

					}
					else
					{ // partsSignMask >= 0
					  // partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
						if (addExponent != 0)
						{
							coefficientMulR.Set(divFactor);

						}
						else
						{ // addExponent != 0
							{ // + divFactor - 1
								Pair96 divFactor96 = new Pair96();
								divFactor96.Set(divFactor);
								divFactor96.Add(new Pair96(0xFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL));
								coefficientMulR.Add(divFactor96);
							}
							coefficientMulR.Div(divFactor);
							coefficientMulR.Mul(divFactor);
						}
						// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor - 1) / divFactor) * divFactor : divFactor;
					}
					break;

				case RoundingMode.HalfUp:
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2) / divFactor) * divFactor : 0;
					if (addExponent != 0)
					{
						coefficientMulR.Set(0, 0);

					}
					else
					{ // addExponent != 0
						{ // + divFactor / 2
							Pair96 divFactor96 = new Pair96();
							divFactor96.Set(divFactor);
							divFactor96.Shr1();
							coefficientMulR.Add(divFactor96);
						}
						coefficientMulR.Div(divFactor);
						coefficientMulR.Mul(divFactor);
					}
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2) / divFactor) * divFactor : 0;
					break;

				case RoundingMode.HalfDown:
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1) / divFactor) * divFactor : 0;
					if (addExponent != 0)
					{
						coefficientMulR.Set(0, 0);

					}
					else
					{ // addExponent != 0
						{ // + divFactor / 2
							Pair96 divFactor96 = new Pair96();
							divFactor96.Set(divFactor);
							divFactor96.Shr1();
							divFactor96.Add(new Pair96(0xFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL));
							coefficientMulR.Add(divFactor96);
						}
						coefficientMulR.Div(divFactor);
						coefficientMulR.Mul(divFactor);
					}
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1) / divFactor) * divFactor : 0;
					break;

				case RoundingMode.HalfEven:
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1 + ((partsCoefficient / divFactor) & 1L)) / divFactor) * divFactor : 0;
					if (addExponent != 0)
					{
						coefficientMulR.Set(0, 0);

					}
					else
					{ // addExponent != 0
						{ // + divFactor / 2
							Pair96 divFactor96 = new Pair96();
							divFactor96.Set(divFactor);
							divFactor96.Shr1();

							bool divisionLatestBit;
							{ // ((partsCoefficient / divFactor) & 1L)
								Pair96 tmpCoefficientMulR = new Pair96(coefficientMulR.w0, coefficientMulR.w21);
								tmpCoefficientMulR.Div(divFactor);

								divisionLatestBit = (tmpCoefficientMulR.w0 & 1) != 0;
							}

							if (!divisionLatestBit)
								divFactor96.Add(new Pair96(0xFFFFFFFFUL, 0xFFFFFFFFFFFFFFFFUL));

							coefficientMulR.Add(divFactor96);
						}
						coefficientMulR.Div(divFactor);
						coefficientMulR.Mul(divFactor);
					}
					// partsCoefficient = addExponent == 0 ? ((partsCoefficient + divFactor / 2 - 1 + ((partsCoefficient / divFactor) & 1L)) / divFactor) * divFactor : 0;
					break;

				case RoundingMode.Unnecessary:
					if (!IsRoundedToReciprocalImpl(addExponent, coefficientMulR, divFactor))
						throw new ArithmeticException("Rounding necessary");

					return value;

				default:
					throw new ArgumentException("Unsupported roundType(=" + roundType + ") value.");
			}

			{ // / r
				coefficientMulR.Div(r);

				if (coefficientMulR.w21 > Int32.MaxValue)
				{
					int dn = NumberOfDigits(coefficientMulR.w21 / Int32.MaxValue);
					uint f = (uint)PowersOfTen[dn];

					partsExponent += dn;

					coefficientMulR.Div(f);
				}

				partsCoefficient = ((LONG_LOW_PART & coefficientMulR.w21) << 32) + coefficientMulR.w0;
			}

			partsExponent += addExponent;
			if (partsCoefficient == 0)
				return Zero;

			BID_UINT32 fpsf = DotNetReImpl.BID_EXACT_STATUS;
			return DotNetReImpl.get_BID64(partsSignMask, partsExponent, partsCoefficient, DotNetReImpl.BID_ROUNDING_TO_NEAREST, ref fpsf);
		}