/// <summary>
        /// <para>Creates a <c>Fraction</c> instance with the 2 parts
        /// of a fraction Y/Z.</para>
        /// <para>Any negative signs are resolved to be on the numerator.</para>
        /// </summary>
        /// <param name="numerator">the numerator, for example the three in 'three sevenths'
        /// </param>
        /// <param name="denominator">the denominator, for example the seven in 'three sevenths'
        /// </param>
        /// <returns>a new fraction instance, with the numerator and denominator reduced</returns>
        /// <exception cref="MathArithmeticException"> if the denominator is <c>zero</c>
        /// </exception>
        public static Fraction getReducedFraction(int numerator, int denominator)
        {
            if (denominator == 0)
            {
                throw new MathArithmeticException(new LocalizedFormats("ZERO_DENOMINATOR_IN_FRACTION"),
                                                  numerator, denominator);
            }
            if (numerator == 0)
            {
                return(ZERO); // normalize zero.
            }
            // allow 2^k/-2^31 as a valid fraction (where k>0)
            if (denominator == Int32.MinValue && (numerator & 1) == 0)
            {
                numerator /= 2; denominator /= 2;
            }
            if (denominator < 0)
            {
                if (numerator == Int32.MinValue ||
                    denominator == Int32.MinValue)
                {
                    throw new MathArithmeticException(new LocalizedFormats("OVERFLOW_IN_FRACTION"),
                                                      numerator, denominator);
                }
                numerator   = -numerator;
                denominator = -denominator;
            }
            // simplify fraction.
            int gcd = ArithmeticUtils.gcd(numerator, denominator);

            numerator   /= gcd;
            denominator /= gcd;
            return(new Fraction(numerator, denominator));
        }
        /// <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)));
        }
        /// <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)));
        }
        /// <summary>
        /// Create a fraction given the numerator and denominator.  The fraction is
        /// reduced to lowest terms.
        /// </summary>
        /// <param name="num">the numerator.</param>
        /// <param name="den">the denominator.</param>
        /// <exception cref="MathArithmeticException"> if the denominator is <c>zero</c>
        /// </exception>
        public Fraction(int num, int den)
        {
            if (den == 0)
            {
                throw new MathArithmeticException(new LocalizedFormats("ZERO_DENOMINATOR_IN_FRACTION"),
                                                  num, den);
            }
            if (den < 0)
            {
                if (num == Int32.MinValue ||
                    den == Int32.MaxValue)
                {
                    throw new MathArithmeticException(new LocalizedFormats("OVERFLOW_IN_FRACTION"),
                                                      num, den);
                }
                num = -num;
                den = -den;
            }
            // reduce numerator and denominator by greatest common denominator.
            int d = ArithmeticUtils.gcd(num, den);

            if (d > 1)
            {
                num /= d;
                den /= d;
            }

            // move sign to numerator.
            if (den < 0)
            {
                num = -num;
                den = -den;
            }
            this.numerator   = num;
            this.denominator = den;
        }