/* ** polyn.cpp ** ** Martin Brain ** address@hidden ** ** Implementation for a polynomial class as specified in polyn.h ** ** Polynomials are stored as an integer representing the order of the polynomial and an array of scalar terms ** representing the coefficients, such that data[i] is the co-efficeint of x^i ** ** Thus the polynomial x^4 + 4x^2 -7x + 26 is ** ** polynomial ** -> order = 4 ** -> data ** -> data[0] = 26 ** -> data[1] = -7 ** -> data[2] = 4 ** -> data[3] = 0 ** -> data[4] = 1 ** */ #include "polyn.h" // Errors static const char *sources[4] = {"Constructor","Copy constructor","Operator =","Operator []"}; static const char *causes[3] = {"Invalid order","Dynamic memory allocation error","Invalid index"}; // Implemnetation of polyException polyException::polyException() { this->source = NULL; this->cause = NULL; } polyException::polyException(char *where, char *what) { this->source = where; this->cause = what; } polyException::polyException(const polyException &oldPolyException) { this->source = oldPolyException.source; this->cause = oldPolyException.cause; } polyException::~polyException() { // Do nothing, as it only contains pointers - not copies of the strings. } polyException & polyException::operator = (polyException &oper) { this->source = oper.source; this->cause = oper.cause; return (*this); } char * polyException::where(void) { return this->source; } char * polyException::what (void) { return this->cause; } // The fundamentals template polynomial::polynomial() { /* Although we could use this to set up a default polynomial of a given order, it is better to just set the elements to 0 and null respectively. This means that the polynomial is more flexible for inheritance. It also saves time because polynomials are likely to be declared without arguments when they are going to be used to hold results, so if this allocated memory, it would only have to be deleted again in the = operator. */ this->order = 0; this->data = NULL; } template polynomial::polynomial(int order) throw(polyException) { register int i; if (order < 0) { throw polyException(*(sources),*(causes)); } this->order = order; try { this->data = new kind[(order + 1)]; } catch(...) { throw polyException(*(sources),*(causes + 1)); } /* Set all of the values to 0, (some implementations of the new operator do this, some don't so its better to assume it doesn't and do it manually). */ for (i = 0; i <= this->order; i++) { *(this->data + i) = 0; } } template polynomial::polynomial(int order, ...) throw(polyException) { va_list ap; if (order < 0) { throw polyException(*(sources),*(causes)); } this->order = order; try { this->data = new kind[(order + 1)]; } catch(...) { throw polyException(*(sources),*(causes + 1)); } va_start(ap); for (/* Nothing needed */; order >= 0; order--) { (this->data + order) = va_arg(ap,kind); } va_end(ap); } template polynomial::polynomial(const polynomial &old) throw(polyException) { register int i; /* Copy across the order */ this->order = old.order; /* Set up the space for the data. */ try { this->data = new kind[(order + 1)]; } catch(...) { throw polyException(*(sources + 1),*(causes + 1)); } /* Copy across the data */ for (i = 0; i <= this->order; i++) { *(this->data + i) = *(old.data + i); } } template polynomial::~polynomial() { delete []data; } // Basic functions template int polynomial::order(void) { return order; } // Operators template polynomial &polynomial::operator = (const polynomial &oper) throw(polyException) { /* Get rid of the old data */ delete []data; /* Copy across the order */ this->order = oper.order; /* Set up the space for the data. */ try { this->data = new kind[(order + 1)]; } catch(...) { throw polyException(*(sources + 2),*(causes + 1)); } /* Copy across the data */ for (i = 0; i <= this->order; i++) { *(this->data + i) = *(oper.data + i); } return (*this); } template polynomial operator + (const polynomial &oper1, const polynomial &oper2) throw(polyException) { /* Set up long as the polynomial with the highest order, short as the other. */ polynomial *long = ((oper1.order >= oper2.order) ? &oper1 : &oper2 ); polynomial *short = ((oper1.order < oper2.order) ? &oper1 : &oper2 ); polynomial sum(&long); register int i; /* Add in the additional terms */ for (i = 0; i <= short->order; i++) { *(sum->data + i) += *(short->data + i); } return sum; } template ostream &operator << (ostream &out, const polynomial &p) { register kind temp; register int i; for (i = p.order; i > 1; i++) { temp = *(p->data + i); /* Using this reduces the number of derefences and thereby increases the program speed. */ if (temp > 0) { out << '+' << temp << "x^" << i; } else if (temp < 0) { out << temp << "x^" << i; } } temp = *(p->data + 1); if (temp > 0) { out << '+' << temp << 'x'; } else if (temp < 0) { out << temp << 'x'; } temp = *(p->data); if (temp > 0) { out << '+' << temp; } else if (temp < 0) { out << temp; } return out; } // Embellishments template kind polynomial::eval(kind at) { register kind power = 1; kind sum = 0; register int i; for (i = 0; i < this->order; i++) { sum += (*(this->data + i) * power); power *= at; } return sum; } template kind &polynomial::operator [](int oper) throw(polyException){ if (oper < 0 || oper > order) { throw polyException(*(sources + 3),*(causes + 2)); } else { return *(this->data + oper); } } template polynomial operator * (const polynomial &oper1, const polynomial &oper2) throw(polyException) { polynomial result(oper1.order + oper2.order); register int i; register int j; for (i = 0; i <= oper1.order; i++) { for (j = 0; j <= oper2.order; j++) { *(result.data + i + j) += *(oper1.data + i) * *(oper2.data + j); } } return result; }