Exemplo n.º 1
0
		/// <summary>
		/// Compares this Fraction to another Fraction
		/// </summary>
		/// <param name="right">The Fraction to compare against</param>
		/// <returns>-1 if this is less than <paramref name="right"></paramref>,
		///  0 if they are equal,
		///  1 if this is greater than <paramref name="right"></paramref></returns>
		public int CompareTo(Fraction right)
		{
			// if left is an indeterminate, punt to the helper...
			if (this.m_Denominator == 0)
			{
				return IndeterminantCompare(NormalizeIndeterminate(this.m_Numerator), right);
			}

			// if right is an indeterminate, punt to the helper...
			if (right.m_Denominator == 0)
			{
				// note sign-flip...
				return - IndeterminantCompare(NormalizeIndeterminate(right.m_Numerator), this);
			}

			// they're both normal Fractions
			CrossReducePair(ref this, ref right);

			try
			{
				checked
				{
					long leftScale = this.m_Numerator * right.m_Denominator;
					long rightScale = this.m_Denominator * right.m_Numerator;

					if (leftScale < rightScale)
						return -1;
					else if (leftScale > rightScale)
						return 1;
					else
						return 0;
				}
			}
			catch (Exception e)
			{
				throw new FractionException(string.Format("CompareTo({0}, {1}) error", this, right), e);
			}
		}
Exemplo n.º 2
0
		/// <summary>
		/// Reduces (simplifies) a Fraction by dividing down to lowest possible denominator (via GCD)
		/// </summary>
		/// <param name="frac">The Fraction to be reduced [WILL BE MODIFIED IN PLACE]</param>
		/// <remarks>Modifies the input arguments in-place! Will normalize the NaN and infinites
		/// representation. Will set Denominator to 1 for any zero numerator. Moves sign to the
		/// Numerator.</remarks>
		/// <example>2/4 will be reduced to 1/2</example>
		public static void ReduceFraction(ref Fraction frac)
		{
			// clean up the NaNs and infinites
			if (frac.m_Denominator == 0)
			{
				frac.m_Numerator = (long)NormalizeIndeterminate(frac.m_Numerator);
				return;
			}

			// all forms of zero are alike.
			if (frac.m_Numerator == 0)
			{
				frac.m_Denominator = 1;
				return;
			}
	            
			long iGCD = GCD(frac.m_Numerator, frac.m_Denominator);
			frac.m_Numerator /= iGCD;
			frac.m_Denominator /= iGCD;
	        
			// if negative sign in denominator
			if ( frac.m_Denominator < 0 )
			{
				//move negative sign to numerator
				frac.m_Numerator = - frac.m_Numerator;
				frac.m_Denominator = - frac.m_Denominator;  
			}
		}
Exemplo n.º 3
0
		/// <summary>
		/// Inverts a Fraction
		/// </summary>
		/// <returns>The inverted Fraction (with Denominator over Numerator)</returns>
		/// <remarks>Does NOT throw for zero Numerators as later use of the fraction will catch the error.</remarks>
		public Fraction Inverse()
		{
			// don't use the obvious constructor because we do not want it normalized at this time
			Fraction frac = new Fraction();

			frac.m_Numerator = this.m_Denominator;
			frac.m_Denominator = this.m_Numerator;
			return frac;
		}
Exemplo n.º 4
0
		/// <summary>
		/// Creates an inverted Fraction
		/// </summary>
		/// <returns>The inverted Fraction (with Denominator over Numerator)</returns>
		/// <remarks>Does NOT throw for zero Numerators as later use of the fraction will catch the error.</remarks>
		public static Fraction Inverted(double value)
		{
			Fraction frac = new Fraction(value);
			return frac.Inverse();
		}
Exemplo n.º 5
0
		/// <summary>
		/// Multiplies two Fractions
		/// </summary>
		/// <param name="left">A Fraction</param>
		/// <param name="right">Another Fraction</param>
		/// <returns>Product of the Fractions. Returns NaN if either Fraction is a NaN.</returns>
		/// <exception cref="FractionException">Will throw if an overflow occurs. Does a cross-reduce to 
		/// insure only the unavoidable overflows occur.</exception>
		private static Fraction Multiply(Fraction left, Fraction right)
		{
			if (left.IsNaN() || right.IsNaN())
				return NaN;

			// this would be unsafe if we were not a ValueType, because we would be changing the
			// caller's values.  If we change back to a class, must use temporaries
			CrossReducePair(ref left, ref right);

			try
			{
				checked
				{
					long numerator = left.m_Numerator * right.m_Numerator;
					long denominator = left.m_Denominator * right.m_Denominator;

					return new Fraction(numerator, denominator);
				}
			}
			catch (Exception e)
			{
				throw new FractionException("Multiply error", e);
			}
		}
Exemplo n.º 6
0
		/// <summary>
		/// Returns the modulus (remainder after dividing) two Fractions
		/// </summary>
		/// <param name="left">A Fraction</param>
		/// <param name="right">Another Fraction</param>
		/// <returns>Modulus of the Fractions. Returns NaN if either Fraction is a NaN.</returns>
		/// <exception cref="FractionException">Will throw if an overflow occurs. Does a cross-reduce to 
		/// insure only the unavoidable overflows occur.</exception>
		private static Fraction Modulus(Fraction left, Fraction right)
		{
			if (left.IsNaN() || right.IsNaN())
				return NaN;

			try
			{
				checked
				{
					// this will discard any fractional places...
					Int64 quotient = (Int64)(left / right);
					Fraction whole = new Fraction(quotient * right.m_Numerator, right.m_Denominator);
					return left - whole;
				}
			}
			catch (Exception e)
			{
				throw new FractionException("Modulus error", e);
			}
		}
Exemplo n.º 7
0
		/// <summary>
		/// Adds two Fractions
		/// </summary>
		/// <param name="left">A Fraction</param>
		/// <param name="right">Another Fraction</param>
		/// <returns>Sum of the Fractions. Returns NaN if either Fraction is a NaN.</returns>
		/// <exception cref="FractionException">Will throw if an overflow occurs when computing the
		/// GCD-normalized values.</exception>
		private static Fraction Add(Fraction left, Fraction right)
		{
			if (left.IsNaN() || right.IsNaN())
				return NaN;

			long gcd = GCD(left.m_Denominator, right.m_Denominator); // cannot return less than 1
			long leftDenominator = left.m_Denominator / gcd;
			long rightDenominator = right.m_Denominator / gcd;

			try
			{
				checked
				{
					long numerator = left.m_Numerator * rightDenominator + right.m_Numerator * leftDenominator;
					long denominator = leftDenominator * rightDenominator * gcd;

					return new Fraction(numerator, denominator);
				}
			}
			catch (Exception e)
			{
				throw new FractionException("Add error", e);
			}
		}
Exemplo n.º 8
0
		/// <summary>
		/// Negates the Fraction
		/// </summary>
		/// <param name="frac">Value to negate</param>
		/// <returns>A new Fraction that is sign-flipped from the input</returns>
		private static Fraction Negate(Fraction frac)
		{
			// for a NaN, it's still a NaN
			return new Fraction( - frac.m_Numerator, frac.m_Denominator);
		}
Exemplo n.º 9
0
		/// <summary>
		/// Determines how this Fraction, of an indeterminate type, compares to another Fraction
		/// </summary>
		/// <param name="leftType">What kind of indeterminate</param>
		/// <param name="right">The other Fraction to compare against</param>
		/// <returns>-1 if this is less than <paramref name="right"></paramref>,
		///  0 if they are equal,
		///  1 if this is greater than <paramref name="right"></paramref></returns>
		/// <remarks>NaN is less than anything except NaN and Negative Infinity. Negative Infinity is less
		/// than anything except Negative Infinity. Positive Infinity is greater than anything except
		/// Positive Infinity.</remarks>
		private static int IndeterminantCompare(Indeterminates leftType, Fraction right)
		{
			switch (leftType)
			{
				case Indeterminates.NaN:
					// A NaN is...
					if (right.IsNaN())
						return 0;	// equal to a NaN
					else if (right.IsNegativeInfinity())
						return 1;	// great than Negative Infinity
					else
						return -1;	// less than anything else

				case Indeterminates.NegativeInfinity:
					// Negative Infinity is...
					if (right.IsNegativeInfinity())
						return 0;	// equal to Negative Infinity
					else
						return -1;	// less than anything else

				case Indeterminates.PositiveInfinity:
					if (right.IsPositiveInfinity())
						return 0;	// equal to Positive Infinity
					else
						return 1;	// greater than anything else

				default:
					// this CAN'T happen, something VERY wrong is going on...
					return 0;
			}
		}
Exemplo n.º 10
0
		/// <summary>
		/// Compares for equality the current Fraction to the value passed.
		/// </summary>
		/// <param name="right">A Fraction to compare against</param>
		/// <param name="notEqualCheck">If true, we're looking for not-equal</param>
		/// <returns>True if the <paramref name="right"></paramref> equals the current 
		/// fraction, false otherwise. If comparing two NaNs, they are always equal AND
		/// not-equal.</returns>
		private bool CompareEquality(Fraction right, bool notEqualCheck)
		{
			// insure we're normalized first
			ReduceFraction(ref this);

			// now normalize the comperand
			ReduceFraction(ref right);

			if (this.m_Numerator == right.m_Numerator && this.m_Denominator == right.m_Denominator)
			{
				// special-case rule, two NaNs are always both equal
				if (notEqualCheck && this.IsNaN())
					return true;
				else
					return ! notEqualCheck;
			}
			else
			{
				return notEqualCheck;
			}
		}
Exemplo n.º 11
0
		/// <summary>
		/// Cross-reduces a pair of Fractions so that we have the best GCD-reduced values for multiplication
		/// </summary>
		/// <param name="frac1">The first Fraction [WILL BE MODIFIED IN PLACE]</param>
		/// <param name="frac2">The second Fraction [WILL BE MODIFIED IN PLACE]</param>
		/// <remarks>Modifies the input arguments in-place!</remarks>
		/// <example>(3/4, 5/9) = (1/4, 5/3)</example>
		public static void CrossReducePair(ref Fraction frac1, ref Fraction frac2)
		{
			// leave the indeterminates alone!
			if (frac1.m_Denominator == 0 || frac2.m_Denominator == 0)
				return;

			long gcdTop = GCD(frac1.m_Numerator, frac2.m_Denominator);
			frac1.m_Numerator = frac1.m_Numerator / gcdTop;
			frac2.m_Denominator = frac2.m_Denominator / gcdTop;

			long gcdBottom = GCD(frac1.m_Denominator, frac2.m_Numerator);
			frac2.m_Numerator = frac2.m_Numerator / gcdBottom;
			frac1.m_Denominator = frac1.m_Denominator / gcdBottom;
		}