Thread: Rational class

  1. #1
    Registered User Kayoss's Avatar
    Join Date
    Sep 2005
    Location
    California
    Posts
    53

    Rational class

    Here is the start of my rational class program. The idea is to add, subtract, multiply and divide two fractions. You can see I've declared 1/3 as the first fraction and 2/5 as the second. However I'm not sure how to point to the 1 separate of the 3, and the 2 separate of the 5, to perform the addition correctly. Do I have to set up numerator1 and numerator2, etc?

    Also, I have a simplify function to reduce the fraction. Currently the first fraction will reduce (for example, if I replaces 1/3 with 4/8 it would return 1/2) but the second will not, and I'm not sure why.

    Code:
    #include <iostream>
    
    using namespace std;
    
    class Rational
    {
       public:
    
          Rational(int n=0,int d=1) 
          {
             numerator = n;
             denominator = d; 
          }
    
          void print() 
          {
             cout << numerator << "/" << denominator << endl;
          }
    
          void operator = (Rational c)
          {
             numerator = c.numerator;
             denominator = c.denominator;
          }
    
          void Rational::simplify() // to simplify the fraction
    	  {
             int n=(int)this->numerator;
             int d=(int)this->denominator;
             int i=2;
    
            while((i<=n) && (n!=1))
           { 
               while((n/i==(int)n/i) && (d/i ==(int)d/i))
               {
                  n/=i;
                  d/=i;
               }
                     i++;
           }
              numerator=n;
              denominator=(n==0)?1:d;
    	  }
    
          Rational operator + (Rational c) // adds fractions
          {
             Rational::simplify();
             Rational t;
             t.numerator = numerator + c.numerator;
             t.denominator = denominator + c.denominator;
             return t;
          }
    
          Rational operator - (Rational c) // subtracts fractions
          {
             Rational::simplify();
             Rational t;
             t.numerator = numerator - c.numerator;
             t.denominator = denominator - c.denominator;
             return t;
          }
    
             Rational operator * (Rational c) // multiplies fractions
            {
                Rational::simplify();
                Rational t;
                t.numerator = numerator * c.numerator;
                t.denominator = denominator * c.denominator;
                return t;
            }
    
            Rational operator / (Rational c) // divides fractions
            {
                Rational::simplify();
                Rational t;
                t.numerator = numerator / c.numerator;
                t.denominator = denominator / c.denominator;
                return t;
             }
    	     
    private:
    
          int numerator;
          int denominator;
    
    }; // end class Rational
    
    int main()
    {
       Rational a(1,3),b(2,5); // a is (1/3); b is (2/5) // a reduces, b does not
       Rational z; // test variable to check default constructor
       Rational c; // instantiates variable c to class Rational initializing to zero
       c = a + b; // currently adds two numerators (1 + 2) and two denominators (3 + 5)
       Rational d; // instantiates d
       d = a - b; // subtracts a from b
       Rational e; //
       e = a*b;
       Rational f;
       f = a/b;
       cout << "First fraction is: " << endl;
       a.print();
       cout << "\nSecond fraction is: " << endl;
       b.print();
       cout << "\nAdding first fraction to second fraction: " << endl;
       c.print();
       cout << "\nSubracting first fraction from second fraction: " << endl;
       d.print();
       cout << "\nMultiplying first fraction to second fraction: " << endl;
       e.print();
       cout << "\nDividing first fraction by second fraction: " << endl;
       f.print();
       cout << "\nTest default fraction: " << endl;
       z.print();
    
    return 0;
    
    }
    THE redheaded stepchild.

  2. #2
    Registered User OnionKnight's Avatar
    Join Date
    Jan 2005
    Posts
    555
    Shouldn't the constructor call Rational::simplify() after assigning the variables?

  3. #3
    Moderately Rabid Decrypt's Avatar
    Join Date
    Feb 2005
    Location
    Milwaukee, WI, USA
    Posts
    300
    However I'm not sure how to point to the 1 separate of the 3, and the 2 separate of the 5
    You've made the numerator and denominator private, which is good, so to allow access to them w/in a program, you'll need to implement accessor functions:

    Code:
    int Rational::get_numerator()
    {
       return numerator;
    }
    Use a similar function for the denominator. This allows anyone using your Rational class in their program to reference the private data members of your class, without allowing direct access (making them public). So in your program, if you want to display the numerator of a, you just:

    Code:
    cout << a.get_numerator();
    There is a difference between tedious and difficult.

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    You refer to simplify as Rational::simplify(), but there is no need for the Rational:: part when you define it inline or call it from the function.

    You don't need the copy assignment operator, it is just doing the default copy.

    Your addition isn't correct mathematically. 1/2 + 2/3 does not equal 3/5. Same for your subtraction. You can have local variables within the addition function to save the non-reduced values when you make the denominators match. If you want you can call them numerator1 and numerator2 and denominator (since the denominator must be the same to add them).

    Your division won't work very well because of problems with integer division. Perhaps you should just flip the second operand and multiply.

    >> a is (1/3); b is (2/5) // a reduces, b does not
    a does not reduce.

    Normally, you want operator+ to be a non-member function that makes a temporary copy of the first operand and then uses += to add the second operand to it, returning the copy. Same for operator-, operator* and operator/. This would mean that you would implement the operations in operator+=, operator-=, operator*= and operator/=.

  5. #5
    Cat without Hat CornedBee's Avatar
    Join Date
    Apr 2003
    Posts
    8,895
    In addition, you should make every member function that does not modify the object const, so that you can call them on const instances.

    Also, your simplify function is broken, again due to integer division. (The gist of it is that (n/i==(int)n/i) is always true if n and i are integers.) If it weren't for integer division, it would still be broken due to precision problems, but the bug would be more subtle.
    All the buzzt!
    CornedBee

    "There is not now, nor has there ever been, nor will there ever be, any programming language in which it is the least bit difficult to write bad code."
    - Flon's Law

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Specializing class
    By Elysia in forum C++ Programming
    Replies: 6
    Last Post: 09-28-2008, 04:30 AM
  2. matrix class
    By shuo in forum C++ Programming
    Replies: 2
    Last Post: 07-13-2007, 01:03 AM
  3. Screwy Linker Error - VC2005
    By Tonto in forum C++ Programming
    Replies: 5
    Last Post: 06-19-2007, 02:39 PM
  4. structure vs class
    By sana in forum C++ Programming
    Replies: 13
    Last Post: 12-02-2002, 07:18 AM