Good evening!

I am currently working with a program that does basic arithmetic with polynomials that can have rational coefficients. I was able to come up with seperate classes and implementation files for my two classes, Polynomial.h and Rational.h. I can run two different programs, one for each class, fine. I am trying to figure out how to use both classes in order to handle the rational coefficients.

The related files:

// Polynomial.h
//#include "Rational.h"
class Polynomial
{
 public:
        static const int maxTerms = 10; // maximum number of terms
        Polynomial(); // constructor
        Polynomial operator+(const Polynomial &) const; // addition
        Polynomial operator-(const Polynomial &) const; // subtraction
        Polynomial operator*(const Polynomial &) const; // multiplication
        Polynomial &operator=(const Polynomial &); // assignment
        Polynomial &operator+=(const Polynomial &);
        Polynomial &operator-=(const Polynomial &);
        Polynomial &operator*=(const Polynomial &);
        void enterTerms();
        void printPolynomial() const;
        int getNumTerms() const;
        int getTermExp(int) const;
        int getTermCoeff(int) const;
        void setCoeff(int, int);
        ~Polynomial(); // destructor
        
 private:
        int numTerms;
        int exp[maxTerms]; // exponent array
        int coeff[maxTerms]; // coefficients array
        static void polyCombine(Polynomial &); // combine commn terms
}; // end class Polynomial

//=====================================================================

// Polynomial.cpp
#include <iostream>
#include <iomanip>
#include "Polynomial.h"
//#include "Rational.h"
using namespace std;

Polynomial::Polynomial()
{
   for(int t = 0; t < maxTerms; t++)
   {
      coeff[t] = 0;
      exp[t] = 0;
   } // end for
   numTerms = 0;
} // end Polynomial constructor

Polynomial Polynomial::operator+(const Polynomial &r) const // addition
{
   Polynomial temp;
   bool expExists;
   int s;
   
   // process element with a zero exponent
   temp.coeff[0] = coeff[0] + r.coeff[0];
   
   // copy right arrays into temp object; s will be used to keep
   // track of first open coefficient element
   for(s = 1; (s < maxTerms) && (r.exp[s] != 0); s++)
   {
      temp.coeff[s] = r.coeff[s];
      temp.exp[s] = r.exp[s];
   } // end for
   for(int x = 1; x < maxTerms; x++)
   {
      expExists = false; // assume exponent will not be found
      
      for(int t = 1; (t < maxTerms) && (!expExists); t++)
        if(exp[x] == temp.exp[t])
        {
           temp.coeff[t] += coeff[x];
           expExists = true; // exponent found
        } // end if
      // exponent was found, insert into temp
      if(!expExists)
      {
         temp.exp[s] = exp[x];
         temp.coeff[s] += coeff[x];
         s++;
      } // end if
   } // endfor
   return temp;
} // end operator+

Polynomial Polynomial::operator-(const Polynomial &r) const // subtraction
{
   Polynomial temp;
   bool expExists;
   int s;
   
   // process element with zero exponent
   temp.coeff[0] = coeff[0] - r.coeff[0];
   
   // copy left arrays into temp object; s will be used to keep
   // track of first open coefficient element
   for(s = 1; (s < maxTerms) && (exp[s] != 0); s++)
   {
      temp.coeff[s] = coeff[s];
      temp.exp[s] = exp[s];
   } // end for
   for (int x = 1; x < maxTerms; x++)
   {
      expExists = false;
      
      for(int t = 1; (t < maxTerms) && (!expExists); t++)
      
        if(r.exp[x] == temp.exp[t])
        {
           temp.coeff[t] -= r.coeff[x];
           expExists = true;
        }
      if(!expExists)
      {
         temp.exp[s] = r.exp[x];
         temp.coeff[s] -= r.coeff[x];
         s++;
      } // end if
   } // end for
} // end operator- function

Polynomial Polynomial::operator*(const Polynomial &r) const // multiplication
{
   Polynomial temp;
   int s = 1;
   
   for(int x = 0; (x < maxTerms) && (x == 0 || coeff[x] != 0); x++)
   
           for(int y = 0; (y < maxTerms) && (y == 0 || r.coeff[y] != 0); y ++)
           
                   if(coeff[x] * r.coeff[y])
                   
                     if((exp[x] == 0) && (r.exp[y] == 0))
                       temp.coeff[0] += coeff[x] * r.coeff[y];
                     else
                     {
                        temp.coeff[s] = coeff[x] * r.coeff[y];
                        temp.exp[s] = exp[x] + r.exp[y];
                        s++;
                     } // end else
   polyCombine(temp); // combine common terms
   return temp;
} // end operator* function


Polynomial &Polynomial::operator=(const Polynomial &r) // assignment
{
   exp[0] = r.exp[0];
   coeff[0] = r.coeff[0];
   
   for(int s = 1; s < maxTerms; s++)
   {
      if(r.exp[s] != 0)
      {
         exp[s] = r.exp[s];
         coeff[s] = r.coeff[s];
      }
      else
      {
         if(exp[s] == 0)
           break;
           
         exp[s] = 0;
         coeff[s] = 0;
      } // end else
   } // end for
   return *this;
} // end operator= function

Polynomial &Polynomial::operator+=(const Polynomial &r)
{
   *this = *this + r;
   return *this;
} // end operator+= function

Polynomial &Polynomial::operator-=(const Polynomial &r)
{
   *this = *this -r;
   return *this;
} // end operator-= function

Polynomial &Polynomial::operator*=(const Polynomial &r)
{
   *this = *this * r;
   return *this;
}// end operator*= function

void Polynomial::enterTerms()
{
   bool found = false;
   int c, e, term;
   
   cout << endl << "Enter number of polynomial terms: ";
   cin >> numTerms;
   
   for(int n = 0; n < maxTerms && n < numTerms; n++)
   {
      cout << endl << "Enter coefficient: ";
      cin >> c;
      cout << "Enter exponent: ";
      cin >> e;
      
      if(c != 0)
      {
         // exponent of zero are forced into first element
         if(e == 0)
         {
            coeff[0] += c;
            continue;
         } // end if
         for(term = 1; (term < maxTerms) && (coeff[term] !=0); term++)
         
           if(e == exp[term])
           {
              coeff[term] += c;
              exp[term] = e;
              found = true; // existing exponent updated
           } // end if
         if(!found) // add term
         {
            coeff[term] += c;
            exp[term] = e;
         } // end if
      } // end outer if
   } // end outer for
} // end enterTerms function

void Polynomial::printPolynomial() const
{
   int start;
   bool zero = false;
   
   if(coeff[0]) // output constraints
   {
      cout << coeff[0];
      start = 1;
      zero = true; // at least one term exists
   }
   else
   {
       if(coeff[1])
       {
          cout << coeff[1] << 'x';
          if((exp[1] != 0) && (exp[1] != 1))
            cout << '^' << exp[1];
          zero = true; // at least one term exists
       } // end if
       start = 2;
   } // end else
   
   // output remaining polynomial terms
   for(int x = start; x < maxTerms; x++)
   {
      if(coeff[x] != 0)
      {
         cout << showpos << coeff[x] << noshowpos << 'x';
         
         if((exp[x] != 0) && (exp[x] != 1))
           cout << '^' << exp[x];
         
         zero = true; // at least one term exists
      } // end if
   } // end for
   if(!zero) // no terms exist in the polynomial
     cout << '0';
     cout << endl;
} // end printPolynomial function

int Polynomial::getNumTerms() const
{
   return numTerms;     
} // end getTerms function

int Polynomial::getTermExp(int term) const
{
   return exp[term];
} // end getTermExp function

int Polynomial::getTermCoeff(int term) const
{
   return coeff[term];
} // end getTermCoeff function

void Polynomial::setCoeff(int term, int coeffs)
{
   if(coeff[term] == 0) // no term at this location
     cout << "No term at this location, cannot see term." << endl;
   else // otherwise set term
     coeff[term] = coeffs;
} // end setCoeff function

void Polynomial::polyCombine(Polynomial &w)
{
   Polynomial temp = w;
   
   // zero out elements of w
   for(int x = 0; x < maxTerms; x++)
   {
      w.coeff[x] = 0;
      w.exp[x] = 0;
   }
   for(int x = 1; x < maxTerms; x++)
   {
      for(int y = x + 1; y < maxTerms; y++)
        if(temp.exp[x] == temp.exp[y])
        {
           temp.coeff[x] += temp.coeff[y];
           temp.exp[y] = 0;
           temp.coeff[y] = 0;
        }
   }
   w = temp;
} // end polyCombine function

Polynomial::~Polynomial() // destructor
{
   // empty
}
// Rational.h
#include <iostream>
using namespace std;
class Rational
{
 private:
                int num;
                int denom;

public:
                void setNum(int);
                void setDenom(int);
                int getNum();
                int getDenom();

                int gcd();
                void simplify();

                Rational operator+(Rational);
                Rational operator-(Rational);
                Rational operator*(Rational);
                Rational operator/(Rational);
                bool operator==(Rational);
                bool operator!=(Rational);
                bool operator>(Rational);
                bool operator<(Rational);
                bool operator>=(Rational);
                bool operator<=(Rational);
};

//=====================================================================

// Rational.cpp
#include <iostream>
#include "Rational.h"
using namespace std;

void Rational::setNum(int n)
{
   num = n;
}

void Rational::setDenom(int n)
{
   denom = n;
}

int Rational::getNum()
{
   return num;
}
int Rational::getDenom()
{
   return denom;
}

int Rational::gcd()
{
   int x = num;
   int y = denom;
   int temp;
 
   while (y)
   {
    temp = y;
    y = x % y;
    x = temp;
   }
   return x;
}

void Rational::simplify()
{
   int gcdNum = gcd();

   if(gcdNum != 0)
   {
    num = num / gcdNum;
    denom = denom / gcdNum;
   }
}

Rational Rational::operator+(Rational passed)
{   
   Rational Result;

   Result.num = num * passed.denom + denom * passed.num;
   Result.denom = denom * passed.denom;
   
   return Result;
}

Rational Rational::operator-(Rational passed)
{
   Rational Result;
   
   Result.num = num * passed.denom - denom * passed.num;
   Result.denom = denom * passed.denom;
   
   return Result;
}

Rational Rational::operator*(Rational passed)
{
   Rational Result;

   Result.num = num * passed.num;
   Result.denom = denom * passed.denom;
   
   return Result;
}


Rational Rational::operator/(Rational passed)
{
   Rational Result;
   Result.num = num * passed.denom;
   Result.denom = denom * passed.num;
   
   return Result;
}

bool Rational::operator==(Rational passed)
{
   simplify();
   passed.simplify();

   return (passed.num == num) && (passed.denom == denom);
}

bool Rational::operator!=(Rational passed)
{
   simplify();  
   passed.simplify();

   return (passed.num != num) && (passed.denom != denom);
}

bool Rational::operator>(Rational passed)
{

   simplify();
   passed.simplify();

   return (num * passed.denom) > (passed.num * denom);
}

bool Rational::operator<(Rational passed)
{
   simplify();
   passed.simplify();

   return (num * passed.denom) < (passed.num * denom);
}

bool Rational::operator>=(Rational passed)
{

   simplify();
   passed.simplify();

   return (num * passed.denom) >= (passed.num * denom);
}

bool Rational::operator<=(Rational passed)
{
   simplify();
   passed.simplify();

   return (num * passed.denom) <= (passed.num * denom);
}

//=====================================================================

Suggestions?

Thanks!

I first off this is an excellent exercise. If you are doing this yourself, well done, if you have a teacher/class, your prof. certainly has found an excellent problem.

So why do I think this is so good, what happened here is that you have designed two classes that can be related. However, when you do try to do that you have a number of issues that could have been avoided if some of the more subtle OO design "rules" had been applied.

First off Rational should be an effective replacement for double. So anywhere in your code that you could write double x; , you could have put, Rational x; . It is not there, yet. Second, polynomial is written to take an integer coefficient. What about the other normal options, e.g. double, matrix, polynomial. [A polynomial of polynomials is mathematically sound and useful.] It should take these options without any significant change to the code.

So what work needs to be done to get to this state:

Make Polynomial more general so that it takes a template type e.g.

template<typename T>
class Polynomial
{  
  public:

  static const int maxTerms = 10; // maximum number of terms

  Polynomial(); // constructor
  // WHERE IS MY COPY CONSTRUCTOR ?????
  Polynomial& operator=(const Polynomial &); 
  ~Polynomial(); 

  Polynomial<T> operator+(const Polynomial<T> &) const; 
  Polynomial<T> operator-(const Polynomial<T> &) const; 
  Polynomial<T> operator*(const Polynomial<T> &) const;

  Polynomial<T>& operator+=(const Polynomial<T>&);
  Polynomial<T>& operator-=(const Polynomial<T>&);
  Polynomial<T>& operator*=(const Polynomial<T>&);
  
  void enterTerms();           // Spelling error corrected
  void printPolynomial() const;
  int getNumTerms() const;
  int getTermExp(int) const;
  const T& getTermCoeff(int) const;  // Note the const reference return
  void setCoeff(int, const T&);   // Note both the reference + const, that avoid
                                  // big copies of expensive classes.
  
private:

  int numTerms;
  int exp[maxTerms]; // exponent array [This is ugly as an array]
  T coeff[maxTerms]; // coefficients array  [This is a lot easier as vector etc.]

  // Why is this a static: it should be this:
  //  void polyCombine();
  static void polyCombine(Polynomial &); 
};

Now I have added a few comments, you get to write the code.

First, even if you don't want to do a templated form, then replace Polynomial<T> with say, PolyRational , you are still going to have to do some work.

The design of using an array, rather than a resizable vector/object AND using the test coeff==0 throughout the code is going to hurt. Use the variable numTerms as the test and Polynomial "converts to a template form" much more readily. Then you only have one place were you have to test that a coeff is zero (or effectively zero) and change the numTerms.

Your used of operator+ as the master and operator+= as the slave, is both inefficient [too many copies] but works under templates.

Be careful with the constructor, that needs a re-think, and you MUST write a copy constructor.

PART B: Rational

Ok the rational class is the templated object, and normally it is the easier to deal with BUT your rational class is much much weaker than your Polynomial class so you are going to have to have a class that is something like this:

class Rational
{
 private:

  int num;
  int denom;
  
public:

  Rational() : num(0),denom(1) {}  // default is useful for polynomial. 
  Rational(const int,const int);
  Rational(const Rational&);
  Rational& operator=(const Rational&);
  ~Rational() {}

  void setNum(int);
  void setDenom(int);
  int getNum();
  int getDenom();
  
  int gcd();
  void simplify();
  
  Rational operator+(const Rational&) const;
  Rational operator-(const Rational&&) const;
  Rational operator*(const Rational&) const;
  Rational operator/(const Rational&) const;
  
  bool operator==(const Rational&) const ;
  bool operator!=(const Rational&);
  bool operator>(const Rational&);
  bool operator<(const Rational&);
  bool operator>=(const Rational&);
  bool operator<=(const Rational&);

  // This will help!!
  void write(std::ostream&) const;
};
// Write this as:
std::ostream& operator<<(std::ostream& outS,const Rational& R)
{
  R.write(outS);
  return outS;
}

You now can put Rational into Polynomial. If you are using template, you may need a couple of template specializations for Polynomial methods, to help out [e.g. printPolynomial/ constructors]

Then all you have to do is construct an object of Polynomial<Rational> and test.
[Note: I recommend starting to test a template form of polynomial with int, then double, before trying Rational. ]


Hope that helps, and (a) please feel free to discuss this further, (b) let us know how you get on.

Edited 6 Years Ago by StuXYZ: n/a

This article has been dead for over six months. Start a new discussion instead.