コード例 #1
0
        /// <summary>
        /// Implement add and subtract using algorithm described in Knuth 4.5.1.
        /// </summary>
        /// <param name="fraction">the fraction to subtract, must not be <c>null</c></param>
        /// <param name="isAdd">true to add, false to subtract</param>
        /// <returns>a <c>Fraction</c> instance with the resulting values</returns>
        /// <exception cref="NullArgumentException"> if the fraction is <c>null</c></exception>
        /// <exception cref="MathArithmeticException"> if the resulting numerator or denominator
        /// cannot be represented in an <c>int</c>.</exception>
        private Fraction addSub(Fraction fraction, Boolean isAdd)
        {
            if (fraction == null)
            {
                throw new NullArgumentException(new LocalizedFormats("FRACTION"));
            }
            // zero is identity for addition.
            if (numerator == 0)
            {
                return(isAdd ? fraction : fraction.negate());
            }
            if (fraction.numerator == 0)
            {
                return(this);
            }
            // if denominators are randomly distributed, d1 will be 1 about 61%
            // of the time.
            int d1 = ArithmeticUtils.gcd(denominator, fraction.denominator);

            if (d1 == 1)
            {
                // result is ( (u*v' +/- u'v) / u'v')
                int uvp = ArithmeticUtils.mulAndCheck(numerator, fraction.denominator);
                int upv = ArithmeticUtils.mulAndCheck(fraction.numerator, denominator);
                return(new Fraction
                           (isAdd ? ArithmeticUtils.addAndCheck(uvp, upv) :
                           ArithmeticUtils.subAndCheck(uvp, upv),
                           ArithmeticUtils.mulAndCheck(denominator, fraction.denominator)));
            }
            // the quantity 't' requires 65 bits of precision; see knuth 4.5.1
            // exercise 7.  we're going to use a BigInteger.
            // t = u(v'/d1) +/- v(u'/d1)
            BigInteger uvpb = new BigInteger(numerator) * new BigInteger(fraction.denominator / d1);
            BigInteger upvb = new BigInteger(fraction.numerator) * new BigInteger(denominator / d1);
            BigInteger t    = isAdd ? (uvpb + upvb) : (uvpb - upvb);
            // but d2 doesn't need extra precision because
            // d2 = gcd(t,d1) = gcd(t mod d1, d1)
            int tmodd1 = Convert.ToInt32(t % (new BigInteger(d1)));
            int d2     = (tmodd1 == 0) ? d1 : ArithmeticUtils.gcd(tmodd1, d1);

            // result is (t/d2) / (u'/d1)(v'/d2)
            BigInteger w = t / (new BigInteger(d2));

            if ((w.ToByteArray().Length / 8) > 31)
            {
                throw new MathArithmeticException(new LocalizedFormats("NUMERATOR_OVERFLOW_AFTER_MULTIPLY"), w);
            }
            return(new Fraction(Convert.ToInt32(w), ArithmeticUtils.mulAndCheck(denominator / d1, fraction.denominator / d2)));
        }
コード例 #2
0
        /// <summary>
        /// <para>Multiplies the value of this fraction by another, returning the
        /// result in reduced form.</para>
        /// </summary>
        /// <param name="fraction">the fraction to multiply by, must not be <c>null</c></param>
        /// <returns>a <c>Fraction</c> instance with the resulting values</returns>
        /// <exception cref="NullArgumentException"> if the fraction is <c>null</c></exception>
        /// <exception cref="MathArithmeticException"> if the resulting numerator or denominator
        /// exceeds <c>Int32.MaxValue</c></exception>
        public Fraction multiply(Fraction fraction)
        {
            if (fraction == null)
            {
                throw new NullArgumentException(new LocalizedFormats("FRACTION"));
            }
            if (numerator == 0 || fraction.numerator == 0)
            {
                return(ZERO);
            }
            // knuth 4.5.1
            // make sure we don't overflow unless the result *must* overflow.
            int d1 = ArithmeticUtils.gcd(numerator, fraction.denominator);
            int d2 = ArithmeticUtils.gcd(fraction.numerator, denominator);

            return(getReducedFraction
                       (ArithmeticUtils.mulAndCheck(numerator / d1, fraction.numerator / d2),
                       ArithmeticUtils.mulAndCheck(denominator / d2, fraction.denominator / d1)));
        }