示例#1
0
        private static int RoundDigit(int sign, uint lastDigit, uint secondLastDigit, BigDecimal.RoundingModes roundingMode)
        {
            int result = -1;

            switch (roundingMode)
            {
            case BigDecimal.RoundingModes.Up:
                if (lastDigit != 0)
                {
                    result = 1;
                }
                break;

            case BigDecimal.RoundingModes.HalfUp:
                if (lastDigit >= 5)
                {
                    result = 1;
                }
                break;

            case BigDecimal.RoundingModes.HalfDown:
                if (lastDigit > 5)
                {
                    result = 1;
                }
                break;

            case BigDecimal.RoundingModes.HalfEven:
                if (lastDigit > 5)
                {
                    result = 1;
                }
                else if ((lastDigit == 5) && (secondLastDigit % 2 != 0))
                {
                    result = 1;
                }
                break;

            case BigDecimal.RoundingModes.Ceiling:
                if (sign == 1 && lastDigit != 0)
                {
                    result = 1;
                }
                break;

            case BigDecimal.RoundingModes.Floor:
                if (sign == -1 && lastDigit != 0)
                {
                    result = 1;
                }
                break;
            }
            return(result);
        }
示例#2
0
        /// <summary>
        /// Limits the precision of the given Fraction.
        /// </summary>
        /// <param name="sign">The sign of the BigDecimal</param>
        /// <param name="fraction">The fraction to limit</param>
        /// <param name="digits">The number of digits to which we are limiting</param>
        /// <param name="mode">The rounding mode to use when limiting</param>
        /// <returns>A new fraction that has no more than <paramref name="digits"/> digits.</returns>
        /// <example>
        /// Consider a fraction of 123456789 using default HalfUp rounding.
        /// Limit : Result
        /// 1       1
        /// 2       12
        /// 3       123
        /// 4       1234
        /// 5       12346
        /// 6       123457
        /// 7       1234568
        /// 8       12345679
        /// 9       123456789
        /// 10      123456789
        /// </example>
        public static Fraction /*!*/ LimitPrecision(int sign, Fraction /*!*/ fraction, int digits, BigDecimal.RoundingModes mode, out int offset)
        {
            Fraction result;

            if (digits <= 0)
            {
                uint digit = (uint)(fraction.IsZero ? 0 : 1);
                if (RoundDigit(sign, digit, 0, mode) > 0)
                {
                    offset = 1 - digits;
                    return(One);
                }
                else
                {
                    offset = 0;
                    return(Zero);
                }
            }

            if (digits >= fraction.DigitCount)
            {
                offset = 0;
                return(fraction);
            }

            // Calculate offsets of relevant digits
            int  secondLastDigitIndex; // i.e. fraction[digits-1]
            int  secondLastWordIndex;
            uint secondLastDigit;
            int  lastDigitIndex; // i.e. fraction[digits]
            int  lastWordIndex;
            uint lastDigit;

#if SILVERLIGHT
            secondLastWordIndex = DivRem(digits - 1, BASE_FIG, out secondLastDigitIndex);
#else
            secondLastWordIndex = System.Math.DivRem(digits - 1, BASE_FIG, out secondLastDigitIndex);
#endif
            if (secondLastDigitIndex == BASE_FIG - 1)
            {
                lastWordIndex  = secondLastWordIndex + 1;
                lastDigitIndex = 0;
            }
            else
            {
                lastWordIndex  = secondLastWordIndex;
                lastDigitIndex = secondLastDigitIndex + 1;
            }

            // TODO: Extract these calculations out into static readonly arrays
            // Mask for last digit.  E.g. lastDigitIndex = 3, BASE_FIG = 9 => lastFactor = 1000000
            uint lastFactor = _powers[lastDigitIndex];
            // Mask for second last digit
            uint secondLastFactor = _powers[secondLastDigitIndex];

            // Calculate the current digits and rounding direction
            secondLastDigit = (fraction._words[secondLastWordIndex] / secondLastFactor) % 10;
            if (lastWordIndex < fraction.MaxPrecision)
            {
                lastDigit = (fraction._words[lastWordIndex] / lastFactor) % 10;
            }
            else
            {
                lastDigit = 0;
            }
            int round = RoundDigit(sign, lastDigit, secondLastDigit, mode);

            // Create a temporary fraction used to cause the rounding in the original
            result = new Fraction(lastWordIndex + 1);
            Array.Copy(fraction._words, 0, result._words, 0, System.Math.Min(lastWordIndex + 1, fraction.Precision));
            // Clear the digits beyond the second last digit
            result._words[secondLastWordIndex] = result._words[secondLastWordIndex] - (fraction._words[secondLastWordIndex] % secondLastFactor);
            if (round > 0)
            {
                // Increment the last digit of result by 1
                Fraction temp = new Fraction(secondLastWordIndex + 1);
                temp._words[secondLastWordIndex] = secondLastFactor;
                result = Fraction.Add(result, temp, 0, out offset);
            }
            else
            {
                offset = 0;
            }

            result.Precision = System.Math.Min(secondLastWordIndex + 1, result.MaxPrecision);
            return(result);
        }