## DamienCurr Newbie Poster

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
{
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!

## StuXYZ 731

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.