예제 #1
0
        public static Fraction /*!*/ Multiply(Fraction /*!*/ x, Fraction /*!*/ y, out int offset)
        {
            int xPrecision = x.Precision;
            int yPrecision = y.Precision;
            int zPrecision = xPrecision + yPrecision;

            uint[]   xData = x._words;
            uint[]   yData = y._words;
            uint[]   zData = new uint[zPrecision];
            Fraction z     = new Fraction(zData);

            for (int xIndex = xPrecision - 1; xIndex >= 0; xIndex--)
            {
                uint  xValue = xData[xIndex];
                int   zIndex = zPrecision - (xPrecision - xIndex);
                ulong carry  = 0;
                for (int yIndex = yPrecision - 1; yIndex >= 0; yIndex--)
                {
                    carry           = carry + ((ulong)xValue) * yData[yIndex] + zData[zIndex];
                    zData[zIndex--] = (uint)(carry % BASE);
                    carry          /= BASE;
                }
                while (carry != 0)
                {
                    carry          += zData[zIndex];
                    zData[zIndex--] = (uint)carry;
                    carry          /= BASE;
                }
            }
            z = Fraction.Normalize(z, out offset);
            return(z);
        }
예제 #2
0
        public static Fraction /*!*/ Subtract(Fraction /*!*/ x, Fraction /*!*/ y, int exponentDiff, out int exponentOffset, out int sign)
        {
            Fraction upper = x;
            Fraction lower = y;

            sign = Compare(x, y, exponentDiff);
            if (sign == 0)
            {
                exponentOffset = 0;
                return(new Fraction(1));
            }
            else if (sign < 0)
            {
                exponentDiff = -exponentDiff;
                upper        = y;
                lower        = x;
            }

            // Calculate the word and digit offsets between upper and lower
            int wordOffset  = exponentDiff / BASE_FIG;
            int digitOffset = exponentDiff % BASE_FIG;

            // If necessary we need to scroll one of the arrays
            if (digitOffset != 0)
            {
                lower = ScrollRight(lower, digitOffset);
            }

            int lowerStart = wordOffset;

            // We should now have something like:
            // UUU UUU UU0 000 000 000 (upperStart=0, upperLength=8)
            // 000 0LL LLL LLL LLL LL0 (lowerStart=4, lowerLength=13)
            // assuming that exponentDiff is 4 (or -4) and BASE_FIG is 3
            // where each character above is a decimal digit and a space indicates a word boundary
            // Also, upper should be larger than lower

            int      zPrecision = System.Math.Max(upper.Precision, lower.Precision + lowerStart);
            Fraction z          = new Fraction(zPrecision);

            uint[] upperWords = upper._words;
            uint[] lowerWords = lower._words;
            uint[] zWords     = z._words;

            // Copy words of upper straight into z
            Array.Copy(upperWords, 0, zWords, 0, upper.Precision);

            //// Subtract words of lower from z, borrowing as necessary
            SubtractInPlace(zWords, lowerWords, lower.Precision, lowerStart);

            z = Fraction.Normalize(z, out exponentOffset);
            return(z);
        }
예제 #3
0
        private static Fraction /*!*/ Parse(string /*!*/ digits, out int digitOffset)
        {
            // Trim off any trailing zeros
            digits = digits.TrimEnd('0');

            if (digits == "")
            {
                digitOffset = 0;
                return(Zero);
            }

            // Create the new fraction
            int precision   = digits.Length / BASE_FIG;
            int finalDigits = digits.Length % BASE_FIG;

            if (finalDigits > 0)
            {
                ++precision;
            }
            Fraction /*!*/ fraction = new Fraction(precision);

            // Iterate through groups of BASE_FIG digits
            int digitIndex;
            int wordIndex = 0;

            for (digitIndex = 0; digitIndex + BASE_FIG <= digits.Length; digitIndex += BASE_FIG)
            {
                fraction._words[wordIndex] = uint.Parse(digits.Substring(digitIndex, BASE_FIG), CultureInfo.InvariantCulture);
                wordIndex++;
            }

            // Add on the last few digits, adding extra zeros as necessary
            if (finalDigits > 0)
            {
                uint lastWord = uint.Parse(digits.Substring(digitIndex), CultureInfo.InvariantCulture);
                while (finalDigits < BASE_FIG)
                {
                    lastWord *= 10;
                    ++finalDigits;
                }
                fraction._words[wordIndex] = lastWord;
            }

            fraction = Fraction.Normalize(fraction, out digitOffset);
            return(fraction);
        }
예제 #4
0
        public static Fraction /*!*/ Add(Fraction /*!*/ x, Fraction /*!*/ y, int exponentDiff, out int exponentOffset)
        {
            Fraction upper = x;
            Fraction lower = y;

            // Switch x and y around if the exponentDiff is negative
            bool swap = exponentDiff < 0;

            if (swap)
            {
                exponentDiff = -exponentDiff;
                upper        = y;
                lower        = x;
            }

            // Calculate the word and digit offsets between upper and lower
            int wordOffset  = exponentDiff / BASE_FIG;
            int digitOffset = exponentDiff % BASE_FIG;

            // If necessary we need to scroll one of the arrays
            if (digitOffset != 0)
            {
                lower = ScrollRight(lower, digitOffset);
            }

            int upperStart = 0;
            int lowerStart = wordOffset;

            // We should now have something like:
            // UUU UUU UU0 000 000 000 (upperStart=0, upperLength=8)
            // 000 0LL LLL LLL LLL LL0 (lowerStart=4, lowerLength=13)
            // assuming that exponentDiff is 4 (or -4) and BASE_FIG is 3
            // where each character above is a decimal digit and a space indicates a word boundary

            int      zPrecision = System.Math.Max(upper.Precision, lower.Precision + wordOffset) + 1;
            Fraction z          = new Fraction(zPrecision);

            uint[] upperWords = upper._words;
            uint[] lowerWords = lower._words;
            uint[] zWords     = z._words;

            // Copy words of lower straight into z
            Array.Copy(lowerWords, 0, zWords, lowerStart + 1, lower.Precision);

            // Add words of upper into z, carrying as necessary
            ulong carry = 0;

            for (int i = upper.Precision - 1; i >= upperStart; i--)
            {
                carry        += upperWords[i] + zWords[i + 1];
                zWords[i + 1] = (uint)(carry % BASE);
                carry        /= BASE;
            }
            Debug.Assert(carry / BASE == 0);
            zWords[0] = (uint)(carry % BASE);

            // We expect there to be BASE_FIG offset when normalizing unless
            // the carry overflowed into the top word.
            z = Fraction.Normalize(z, out exponentOffset);
            exponentOffset += BASE_FIG;
            return(z);
        }