Population

Cartesian

    A.First Edition

    This is my first edition of a simple assignment of C++. And I hesitate for some time to decide whether to add it.

    B.The problem

    	Assignment #2
    		=============

    Create a class Fraction which is composed of private "numerator" and
    "denominator" data members.

    Your class must contain the following:

    1. constructor (including default arguments numerator = denominator = 1)
    2. print method (print in the form "numerator/denominator"
    3. add function
    4. subtract function
    5. multiply function
    6. divide function

    * The add, subtract, multiply, and divide functions should be "friends" of the
      Fraction class.  Each function must receive two constant references to
      Fraction objects as arguments and return a Fraction.  Furthermore, these
      functions must reduce the resulting fraction to the lowest common denominator.

    * The constructor should also reduce the fraction to the lowest common
      denominator. (Hint: You may want to write a private function to reduce
      to the LCD.)

    * Note that negative fractions are allowed.  The negative sign should always
      be associated with the numerator.

    **************************************************************************
    * Ensure that constant Fraction object may be created, used and printed. *
    **************************************************************************

    * Remember that a denominator should never be zero! Don't forget to handle it!

    * Document (i.e. comment) your code well!!!!!!!

    * You MUST use the driver program given below!!!

C.The idea of program

    There is only a few points worth mentioning.

    1. How to find LCM? My way is to find GCD and then use theorem that the product of two number is equal to product

    of their LCM and GCD. As for GCD, it is very easy to get by Euclidean Algorithm.

    2. How to make const objects possible? You must implement all those functions that might be used by const objects

    and make sure they are all const. Or in other words, they all have a const key word to make "this" pointer const.

    Remember const must also appear in definition of functions.

    D.The major functions

    1. int GCD(int first, int second)

    This is another one for Euclidean Algorithm, I remember that at least I implemented it for three times.(including

    assembly.)

    C.Further improvement

    1. All the four friend functions return an object and this implies a dynamic allocated object must be created.

    Then who would delete them?

    2. Friend functions cannot access member functions of class. And I have to make GCD a friend function either

    which is meaningless.

    กก

    #include <iostream>

    using namespace std;

    enum FractionName
    {Numerator, Denominator};

    class Fraction
    {
    	friend Fraction& add(const Fraction& first, const Fraction& second);
    	friend Fraction& subtract(const Fraction& first, const Fraction& second);
    	friend Fraction& multiply(const Fraction& first, const Fraction& second);
    	friend Fraction& divide(const Fraction& first, const Fraction& second);
    	friend int GCD(int first, int second);
    private:
    	int denominator;
    	int numerator;
    	void reduceForm();

    public:
    	void print() const;
    	Fraction(int num=1, int den=1);
    };

    int main()
    {
    	Fraction F;

       // TEST ZERO DEMONINATOR
        Fraction f0(1,0) ;              // uh-oh! constructor should handle it
        cout << "Fraction f0(1,0) = " ;
        f0.print() ;                   			//should NOT print "1/0"
        cout << endl ;

        // TEST REDUCE LOWEST COMMON DENOMINATOR
        Fraction f1(2,6) ;              		// should reduce to 1/3
        cout << "Fraction f1(2,6) = " ;
        f1.print() ;                    		// should print "1/3"
        cout << endl ;

        Fraction f2(1024,8) ;           		// reduces to 128/1
        cout << "Fraction f2(1024,8) = " ;
        f2.print() ;					// should print "128"
        cout << endl ;

    	// TEST NEGATIVE FRACTION
        Fraction fneg(3,-7) ;
        cout << "Fraction fneg(3,-7) = " ;
        fneg.print() ;                    		// should print "-3/7"
        cout << endl ;

        // TEST const FRACTION CREATION
        const Fraction half(1,2) ;
        cout << "const Fraction half(1,2) = " ;
        half.print() ;					// should print "1/2"
        cout << endl ;

        // TEST ADD FUNCTION
        Fraction Fa ;					// defaults to 1/1
        Fa = add( f1, f2 ) ;				// memberwise copy
        cout << "Fa = add( f1, f2 ) = " ;
        Fa.print() ;					// should print "385/3"
        cout << endl ;

        cout << "add( f1, half ).print() = " ;
        add( f1, half ).print() ;			// should print "5/6"
        cout << endl ;

        // TEST SUBTRACT FUNCTION
        cout << "subtract( half, fneg ).print() = " ;
        subtract( half, fneg ).print() ;		// should print "13/14"
        cout << endl ;

    	cout << "subtract( f1, Fa ).print() = " ;
        subtract( f1, Fa ).print() ;			// should print "-128"
        cout << endl ;

        // TEST MULTIPLY FUNCTION
        cout << "multiply( f1, fneg ).print() = " ;
        multiply( f1, fneg ).print() ;			// should print "-1/7"
        cout << endl ;

        // TEST DIVIDE FUNCTION
        cout << "divide( f1, fneg ).print() = " ;
        divide( f1, Fa ).print() ;			// should print "1/385"
        cout << endl ;

    	return 0;
    }

    //denominator may be input 0 or negative, which should be handled
    Fraction::Fraction(int num, int den)
    {
    	numerator = num;
    	if (den==0)
    	{
    		cout<<"uh-oh!Denominator is 0! And it is set to 1 now.\n";
    		denominator = 1;
    	}
    	else
    	{
    		//I need to keep denominator to be positive always
    		if (den<0)
    		{
    			denominator = den*(-1);
    			numerator *= -1;//the sign should be carried by numerator
    		}
    		else
    		{
    			denominator = den;
    		}
    	}
    	reduceForm();
    }

    //I need to find the GCD which must be positive
    void Fraction::reduceForm()
    {
    	int divisor;
    	//the divisor must be positive
    	divisor = GCD(abs(numerator), denominator);
    	if (divisor!=1)
    	{
    		numerator /= divisor;
    		denominator /= divisor;
    	}
    }

    void Fraction::print() const
    {
    	cout<<(numerator<0?'-':' ')<<abs(numerator)<<'/'<<denominator<<endl;
    }

    //Using Euclidean Algorithms to find GCD
    int GCD(int first, int second)
    {
    	div_t result; //this is a built-in struct
    	int divider = first;
    	int divisor = second;
    	result = div(divider, divisor);
    	while (result.rem!=0)
    	{
    		divider = divisor;
    		divisor = result.rem;

    		result = div(divider, divisor);
    	}

    	return divisor;
    }

    Fraction& add(const Fraction& first, const Fraction& second)
    {
    	int gcd, lcm;
    	int newNum;
    	gcd = GCD(first.denominator, second.denominator);
    	//a theorem: product of two number equal product of their GCD and LCM
    	lcm = first.denominator * second.denominator / gcd;

    	newNum = lcm / first.denominator * first.numerator;
    	newNum += lcm/second.denominator * second.numerator;

    	Fraction* Result = new Fraction (newNum, lcm);
    	return *Result;
    }

    Fraction& subtract(const Fraction& first, const Fraction& second)
    {
    	int gcd, lcm;
    	int newNum;
    	gcd = GCD(first.denominator, second.denominator);
    	//a theorem: product of two number equal product of their GCD and LCM
    	lcm = first.denominator * second.denominator / gcd;

    	newNum = lcm / first.denominator * first.numerator;
    	newNum -= lcm/second.denominator * second.numerator;

    	Fraction* Result = new Fraction(newNum, lcm);
    	return *Result;
    }

    Fraction& multiply(const Fraction& first, const Fraction& second)
    {
    	Fraction* Result =
    		new Fraction(first.numerator*second.numerator, first.denominator*second.denominator);
    	return *Result;
    }

    Fraction& divide(const Fraction& first, const Fraction& second)
    {
    	Fraction* Result =
    		new Fraction (first.numerator*second.denominator, first.denominator*second.numerator);
    	return *Result;
    }