#ifndef POLYNOMIAL_H
#define POLYNOMIAL_H
#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
namespace Doug { // end of namespace at end of file
class Monomial {
friend class Polynomial;
public:
Monomial( const double ctorCoefficient = 0, const double ctorExponent = 0 )
: coefficient(ctorCoefficient), exponent(ctorExponent) {
; // constructor not used by current driver but made
// available for other drivers that might
}
Monomial( const Monomial& m ) {
coefficient = m.coefficient;
exponent = m.exponent;
}
~Monomial() {
; // nothing needs to be done
}
// Getters and setters are provided for classes that
// may wish to utilize Monomials but which are not
// friend classes. Polynomials are closely related
// to Monomials and so are made a friend class with
// full access to the internal data of a Monomial.
// This is more efficient, and not a great risk.
// With the benefit of hindsight, Monomial might have
// been better implemented as a struct or as std::pair
// because it doesnt really provide any behavior...
// ...except the operator== which may justify it being
// a class... although it could be a struct with a
// non-member operator==
void setCoefficient(double newCoefficient) {
coefficient = newCoefficient;
}
void setExponent(double newExponent) {
exponent = newExponent;
}
double getCoefficient() const {
return coefficient;
}
double getExponent() const {
return exponent;
}
// Operator== is used in the std::remove operation
// which is used in Polynomial operator-=
bool operator==(const Monomial& rhs) {
if ( coefficient == rhs.coefficient && exponent == rhs.exponent ) {
// if they are exactly equal, they match
return true;
} else if ( coefficient == 0 && rhs.coefficient == 0 ) {
// the exponent doesn't matter if they coefficients are 0
// so they match if their coefficients are both 0
return true;
} else { // not a match
return false;
}
}
private:
double coefficient; // aka constant, multiplied by variable
double exponent; // ... whole number exponent aka degree
};
class Polynomial {
public:
Polynomial() {
; // nothing needs to be done
}
Polynomial ( const Polynomial& p ) {
// copy constructor not used for current driver
// but may be used by other drivers
this->terms = p.terms;
}
~Polynomial() {
; // nothing needs to be done
}
void enterTerms() {
// appends inputted terms to the polynomial
std::string input("y");
do {
if ( input.length() == 1 && tolower(input[0]) == 'y' ) {
enterTerm();
} else if ( (input.length() == 1 && tolower(input[0]) != 'n' ) || input.length() > 1 ) {
std::cout << "\n Invalid input.";
}
std::cout << "\n Another term? (Y/N) : > ";
std::cin.ignore();
std::getline(std::cin, input);
} while( tolower(input[0]) != 'n' || input.length() > 1 );
}
// intentionally left available to driver programs even
// though it is not utilized in the test driver
void enterTerm() {
Monomial monomial;
std::string input;
std::cout << "\n Enter coefficient : > ";
std::cin >> monomial.coefficient;
// std::cout << "\n Coefficient is : " << monomial.coefficient;
std::cout << "\n Enter exponent : > ";
std::cin >> monomial.exponent;
// std::cout << "\n Exponent is : " << monomial.exponent;
terms.push_back(monomial);
}
/* determined to be unnecessary but might be
reimplemented for some purpose later
Monomial getTerm(const size_t term) const {
return terms[term];
}*/
void printPolynomial() const {
if ( terms.size() > 0 ) {
for ( size_t i = 0; i < terms.size(); ++i ) {
printTerm(i);
if ( i < terms.size() - 1 ) {
std::cout << " + ";
}
}
} else {
std::cout << '0';
}
}
Polynomial operator+=( const Polynomial& rhs ) {
for ( std::vector<Monomial>::const_iterator rTerm = rhs.terms.begin();
rTerm != rhs.terms.end(); ++rTerm ) {
bool match = false;
for ( std::vector<Monomial>::iterator term = terms.begin();
term != terms.end(); ++term ) {
// loop through each of the current object's terms
// and if they have the same exponent, add their coefficients
if ( term->exponent == rTerm->exponent ) {
term->coefficient += rTerm->coefficient;
match = true;
break;
}
}
// if there is no term with the same exponent
// then add the term as a new separate term
if ( match == false ) {
terms.push_back(*rTerm);
}
}
return *this;
}
Polynomial operator-=( const Polynomial& rhs ) {
for ( std::vector<Monomial>::const_iterator rTerm = rhs.terms.begin();
rTerm != rhs.terms.end(); ++rTerm ) {
bool match = false;
for ( std::vector<Monomial>::iterator term = terms.begin();
term != terms.end(); ++term ) {
// loop through each of the current object's terms
// and if they have the same exponent, subtract the coefficient
if ( term->exponent == rTerm->exponent ) {
term->coefficient -= rTerm->coefficient;
match = true;
break;
}
}
// if there is no term with the same exponent
// then add the term as a new separate term
if ( match == false ) {
terms.push_back(*rTerm);
terms.back().coefficient -= terms.back().coefficient * 2;
}
}
// remove terms that have been negated/cancelled out
const Monomial zero;
terms.erase(std::remove(terms.begin(), terms.end(), zero), terms.end());
return *this;
}
Polynomial operator*=( const Polynomial& rhs ) {
Polynomial products;
// x*x becomes x^2, 2x*x becomes 2x^2
// x^2 * x^2 becomes x^4 ie. x*x * x*x = x*x*x*x
// (x + x^2) + (x + x^2) = 2x + 2x^2;
// (x + x^2) * (x + x^2) = x^2 + x^3 + x^3 + x^4 = x^2 + 2x^3 + x^4
// above are examples used to design the algorithm
for ( std::vector<Monomial>::const_iterator rTerm = rhs.terms.begin();
rTerm != rhs.terms.end(); ++rTerm ) {
for ( std::vector<Monomial>::iterator term = terms.begin();
term != terms.end(); ++term ) {
// create a new term for each combination of terms from lhs & rhs
// and do simple multiplication that way, then add the products
products.terms.push_back(*term);
products.terms.back().coefficient *= rTerm->coefficient;
products.terms.back().exponent += rTerm->exponent;
}
}
terms.clear(); // remove all terms from this polynomial
*this += products; // uses += because the way += works will combine terms
// with the same exponent
return *this;
}
Polynomial operator+( const Polynomial& rhs ) {
return Polynomial(*this) += rhs;
}
Polynomial operator-( const Polynomial& rhs ) {
return Polynomial(*this) -= rhs;
}
Polynomial operator*( const Polynomial& rhs ) {
return Polynomial(*this) *= rhs;
}
Polynomial operator=( const Polynomial& rhs ) {
terms = rhs.terms;
return *this;
}
private:
void printTerm(const size_t term) const {
// printTerm is of no use aside from as a utility of
// the printPolynomial public function
std::cout << terms[term].coefficient << 'x';
if ( terms[term].exponent > 1) {
std::cout << '^' << terms[term].exponent;
}
}
std::vector<Monomial> terms;
};
} // end of namespace Doug
#endif