Class name: Fraction Developed by: Syed Mehroz Alam Email: [email protected] URL: Programming Home "http://www.geocities.com/smehrozalam/" Version: 2.0 What's new in version 2.0: * Changed Numerator and Denominator from Int32(integer) to Int64(long) for increased range * renamed ConvertToString() to (overloaded) ToString() * added the capability of detecting/raising overflow exceptions * Fixed the bug that very small numbers e.g. 0.00000001 could not be converted to fraction * Other minor bugs fixed Properties: Numerator: Set/Get value for Numerator Denominator: Set/Get value for Numerator Value: Set an integer value for the fraction Constructors: no arguments: initializes fraction as 0/1 (Numerator, Denominator): initializes fraction with the given numerator and denominator values (integer): initializes fraction with the given integer value (long): initializes fraction with the given long value (double): initializes fraction with the given double value (string): initializes fraction with the given string value the string can be an in the form of and integer, double or fraction. e.g it can be like "123" or "123.321" or "123/456" Public Methods (Description is given with respective methods' definitions) (override) string ToString(Fraction) Fraction ToFraction(string) Fraction ToFraction(double) double ToDouble(Fraction) Fraction Duplicate() Fraction Inverse(integer) Fraction Inverse(Fraction) ReduceFraction(Fraction) Equals(object) GetHashCode() Private Methods (Description is given with respective methods' definitions) Initialize(Numerator, Denominator) Fraction Negate(Fraction) Fraction Add(Fraction1, Fraction2) Overloaded Operators (overloaded for Fractions, Integers and Doubles) Unary: - Binary: +,-,*,/ Relational and Logical Operators: ==,!=,<,>,<=,>= Overloaded user-defined conversions Implicit: From double/long/string to Fraction Explicit: From Fraction to double/string
 public MatrixClass(int[,] elements)
 {
     m_iRows = elements.GetLength(0);
     m_iCols = elements.GetLength(1); ;
     m_iElement = new Fraction[m_iRows, m_iCols];
     for (int i = 0; i < elements.GetLength(0); i++)
     {
         for (int j = 0; j < elements.GetLength(1); j++)
         {
             this[i, j] = new Fraction(elements[i, j]);
         }
     }
 }
 /// <summary>
 /// The function returns a Scalar MatrixClass of dimension ( Row x Col ) and scalar K
 /// </summary>
 public static MatrixClass ScalarMatrixClass(int iRows, int iCols, int K)
 {
     Fraction zero = new Fraction(0);
     Fraction scalar = new Fraction(K);
     MatrixClass MatrixClass = new MatrixClass(iRows, iCols);
     for (int i = 0; i < iRows; i++)
         for (int j = 0; j < iCols; j++)
         {
             if (i == j)
                 MatrixClass[i, j] = scalar;
             else
                 MatrixClass[i, j] = zero;
         }
     return MatrixClass;
 }
 /// <summary>
 /// internal function for negation
 /// </summary>
 private static Fraction Negate(Fraction frac1)
 {
     long iNumerator = -frac1.Numerator;
     long iDenominator = frac1.Denominator;
     return (new Fraction(iNumerator, iDenominator));
 }
 /// <summary>
 /// Constructors
 /// </summary>
 public MatrixClass(Fraction[,] elements)
 {
     m_iElement = elements;
     m_iRows = elements.GetLength(0);
     m_iCols = elements.GetLength(1);
 }
 /// <summary>
 /// The function replicates current Fraction object
 /// </summary>
 public Fraction Duplicate()
 {
     Fraction frac = new Fraction();
     frac.Numerator = Numerator;
     frac.Denominator = Denominator;
     return frac;
 }
 private static Fraction Multiply(Fraction frac1, Fraction frac2)
 {
     try
     {
         checked
         {
             long iNumerator = frac1.Numerator * frac2.Numerator;
             long iDenominator = frac1.Denominator * frac2.Denominator;
             return (new Fraction(iNumerator, iDenominator));
         }
     }
     catch (OverflowException)
     {
         throw new FractionException("Overflow occurred while performing arithemetic operation");
     }
     catch (Exception)
     {
         throw new FractionException("An error occurred while performing arithemetic operation");
     }
 }
 /// <summary>
 /// The function takes a Fraction object and returns its value as double
 /// </summary>
 public static double ToDouble(Fraction frac)
 {
     return ((double)frac.Numerator / frac.Denominator);
 }
 /// <summary>
 /// The function multiplies the given row of the current MatrixClass object by a Fraction 
 /// </summary>
 public void MultiplyRow(int iRow, Fraction frac)
 {
     for (int j = 0; j < this.Cols; j++)
     {
         this[iRow, j] *= frac;
         Fraction.ReduceFraction(this[iRow, j]);
     }
 }
        /// <summary>
        /// The function returns the inverse of a Fraction object
        /// </summary>
        public static Fraction Inverse(Fraction frac1)
        {
            if (frac1.Numerator == 0)
                throw new FractionException("Operation not possible (Denominator cannot be assigned a ZERO Value)");

            long iNumerator = frac1.Denominator;
            long iDenominator = frac1.Numerator;
            return (new Fraction(iNumerator, iDenominator));
        }
        /// <summary>
        /// The function reduces(simplifies) a Fraction object by dividing both its numerator 
        /// and denominator by their GCD
        /// </summary>
        public static void ReduceFraction(Fraction frac)
        {
            try
            {
                if (frac.Numerator == 0)
                {
                    frac.Denominator = 1;
                    return;
                }

                long iGCD = GCD(frac.Numerator, frac.Denominator);
                frac.Numerator /= iGCD;
                frac.Denominator /= iGCD;

                if (frac.Denominator < 0)	// if -ve sign in denominator
                {
                    //pass -ve sign to numerator
                    frac.Numerator *= -1;
                    frac.Denominator *= -1;
                }
            } // end try
            catch (Exception exp)
            {
                throw new FractionException("Cannot reduce Fraction: " + exp.Message);
            }
        }
 private void SetElement(int iRow, int iCol, Fraction value)
 {
     if (iRow < 0 || iRow > Rows - 1 || iCol < 0 || iCol > Cols - 1)
         throw new MatrixClassException("Invalid index specified");
     m_iElement[iRow, iCol] = value.Duplicate();
 }
 /// <summary>
 /// The helper function for the above Determinent() method
 /// it calls itself recursively and computes determinent using minors
 /// </summary>
 private Fraction Determinent(MatrixClass MatrixClass)
 {
     Fraction det = new Fraction(0);
     if (MatrixClass.Rows != MatrixClass.Cols)
         throw new MatrixClassException("Determinent of a non-square MatrixClass doesn't exist");
     if (MatrixClass.Rows == 1)
         return MatrixClass[0, 0];
     for (int j = 0; j < MatrixClass.Cols; j++)
         det += (MatrixClass[0, j] * Determinent(MatrixClass.Minor(MatrixClass, 0, j)) * (int)System.Math.Pow(-1, 0 + j));
     return det;
 }
 private static MatrixClass Multiply(MatrixClass MatrixClass, Fraction frac)
 {
     MatrixClass result = new MatrixClass(MatrixClass.Rows, MatrixClass.Cols);
     for (int i = 0; i < MatrixClass.Rows; i++)
         for (int j = 0; j < MatrixClass.Cols; j++)
             result[i, j] = MatrixClass[i, j] * frac;
     return result;
 }
 /// <summary>
 /// The function returns a Unit MatrixClass of dimension ( Row x Col )
 /// </summary>
 public static MatrixClass UnitMatrixClass(int iRows, int iCols)
 {
     Fraction temp = new Fraction(1);
     MatrixClass MatrixClass = new MatrixClass(iRows, iCols);
     for (int i = 0; i < iRows; i++)
         for (int j = 0; j < iCols; j++)
             MatrixClass[i, j] = temp;
     return MatrixClass;
 }
 /// <summary>
 /// The function takes a floating point number as an argument 
 /// and returns its corresponding reduced fraction
 /// </summary>
 public static Fraction ToFraction(double dValue)
 {
     try
     {
         checked
         {
             Fraction frac;
             if (dValue % 1 == 0)	// if whole number
             {
                 frac = new Fraction((long)dValue);
             }
             else
             {
                 double dTemp = dValue;
                 long iMultiple = 1;
                 string strTemp = dValue.ToString();
                 while (strTemp.IndexOf("E") > 0)	// if in the form like 12E-9
                 {
                     dTemp *= 10;
                     iMultiple *= 10;
                     strTemp = dTemp.ToString();
                 }
                 int i = 0;
                 while (strTemp[i] != '.')
                     i++;
                 int iDigitsAfterDecimal = strTemp.Length - i - 1;
                 while (iDigitsAfterDecimal > 0)
                 {
                     dTemp *= 10;
                     iMultiple *= 10;
                     iDigitsAfterDecimal--;
                 }
                 frac = new Fraction((int)Math.Round(dTemp), iMultiple);
             }
             return frac;
         }
     }
     catch (OverflowException)
     {
         throw new FractionException("Conversion not possible due to overflow");
     }
     catch (Exception)
     {
         throw new FractionException("Conversion not possible");
     }
 }
 /// <summary>
 /// The function adds two rows for current MatrixClass object
 /// It performs the following calculation:
 /// iTargetRow = iTargetRow + iMultiple*iSecondRow
 /// </summary>
 public void AddRow(int iTargetRow, int iSecondRow, Fraction iMultiple)
 {
     for (int j = 0; j < this.Cols; j++)
         this[iTargetRow, j] += (this[iSecondRow, j] * iMultiple);
 }
        /// <summary>
        /// The function returns the determinent of the current MatrixClass object as Fraction
        /// It computes the determinent by reducing the MatrixClass to reduced echelon form using row operations
        /// The function is very fast and efficient but may raise overflow exceptions in some cases.
        /// In such cases use the Determinent() function which computes determinent in the traditional 
        /// manner(by using minors)
        /// </summary>
        public Fraction DeterminentFast()
        {
            if (this.Rows != this.Cols)
                throw new MatrixClassException("Determinent of a non-square MatrixClass doesn't exist");
            Fraction det = new Fraction(1);
            try
            {
                MatrixClass ReducedEchelonMatrixClass = this.Duplicate();
                for (int i = 0; i < this.Rows; i++)
                {
                    if (ReducedEchelonMatrixClass[i, i] == 0)	// if diagonal entry is zero,
                        for (int j = i + 1; j < ReducedEchelonMatrixClass.Rows; j++)
                            if (ReducedEchelonMatrixClass[j, i] != 0)	 //check if some below entry is non-zero
                            {
                                ReducedEchelonMatrixClass.InterchangeRow(i, j);	// then interchange the two rows
                                det *= -1;	//interchanging two rows negates the determinent
                            }

                    det *= ReducedEchelonMatrixClass[i, i];
                    ReducedEchelonMatrixClass.MultiplyRow(i, Fraction.Inverse(ReducedEchelonMatrixClass[i, i]));

                    for (int j = i + 1; j < ReducedEchelonMatrixClass.Rows; j++)
                    {
                        ReducedEchelonMatrixClass.AddRow(j, i, -ReducedEchelonMatrixClass[j, i]);
                    }
                    for (int j = i - 1; j >= 0; j--)
                    {
                        ReducedEchelonMatrixClass.AddRow(j, i, -ReducedEchelonMatrixClass[j, i]);
                    }
                }
                return det;
            }
            catch (Exception)
            {
                throw new MatrixClassException("Determinent of the given MatrixClass could not be calculated");
            }
        }