next up previous contents
Next: Integration: Up: Implementation: The Complex_POLY_CELL Class: Previous: Mergesort:

Arithmetic Operators:

Let's start with the addition operator. This one is used in code fragments like this:

Complex_POLY R,P,P2;
//assume P and P2 have been built somehow
R = P + P2;

The overloaded + operator is called to handle the P + P2 portion of the line and the result is returned to the right hand side so that the overloaded equal can be used update R. Note that addition is accomplished by using the insert_nosort() method so to delay sorting of the answer until the process is finished.

    // ************************************ //
    // Overloaded Operator +                //
    // ************************************ //
Complex_POLY Complex_POLY::operator+(const Complex_POLY& P)
{
  unsigned int p;
  Complex_POLY *RESULT; 
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    //cout << "Both this and incoming polynomial are degenerate" << endl; 
    RESULT = new Complex_POLY();
    return(*RESULT);
    }
  if(head!=NULL && P.head==NULL){
    //we add nothing, so return *this
    return(*this);
    }
  if(head==NULL && P.head!=NULL){
    //*this is NULL, so return incoming P
    *RESULT = P;
    return(*RESULT);
    }
  if(head!=NULL && P.head!=NULL){
    RESULT = new Complex_POLY();
    *RESULT = *this;
    Complex_POLY_CELL* temp;
    for(ComplexPOLYIter next(P);next;++next){
      temp = next();
      RESULT->insert_nosort(temp->element,temp->power);
      }
    //insertions done, so now sort
    RESULT->mergesort();  
    return(*RESULT);
    }
}

Similar comments can be made about the subtraction operator.

    // ************************************ //
    //        Overloaded Operator -         //
    // ************************************ //
Complex_POLY Complex_POLY::operator-(const Complex_POLY& P)
{
  unsigned int p;
  Complex_POLY *RESULT;
  Complex s;
   
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    //cout << "Both this and incoming polynomial are degenerate" << endl;
    RESULT = new Complex_POLY();
    return(*RESULT);
    }
  if(head!=NULL && P.head==NULL){
    //we subtract nothing, so return *this
    return(*this);
    }
  if(head==NULL && P.head!=NULL){
    //*this is NULL, so return -P
    RESULT = new Complex_POLY();
    *RESULT = P;
    Complex_POLY_CELL* temp;
    temp = RESULT->head;
    temp->element *= -1.0;
    while(temp->next!=NULL){
      temp->next->element *= -1.0;
      temp = temp->next;
      }
    return(*RESULT);
    }
  if(head!=NULL && P.head!=NULL){
    //both *this and P are non NULL
    RESULT = new Complex_POLY();
    *RESULT = *this;
    Complex_POLY_CELL* temp;
    temp = P.head;
    s = -1.0*(temp->element);
    RESULT->insert_nosort(s,temp->power);
    while(temp->next!=NULL){
      s = -1.0*(temp->next->element);
      RESULT->insert_nosort(s,temp->next->power);
      temp = temp->next;
      }
    return(*RESULT);
    }
}

The next two operators involve + = and - = operations which must be handled differently than the usual + and - respectively. The main difference between this code and the stuff above is that the insertions are made into the this pointer that points to the left hand side. This kind of code shows up in fragments like

Complex_POLY S,R,P;
//assume they have been built somehow
R += P;
S -= R;
    // ************************************ //
    // Overloaded Operator +=               //
    // ************************************ //
Complex_POLY& Complex_POLY::operator+=(const Complex_POLY& P)
{
  unsigned int p;
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    //cout << "Both this and incoming polynomial are degenerate" << endl;
    return(*this);
    }
  if(head!=NULL && P.head==NULL){
    //we add nothing, so return *this
    return(*this);
    }
  if(head==NULL && P.head!=NULL){
    //*this is NULL, so return incoming P
    *this = P;
    return(*this);
    }
  if(head!=NULL && P.head!=NULL){
    //both *this and P are non NULL
    Complex_POLY_CELL* temp;
    temp = P.head;
    insert_nosort(temp->element,temp->power);
    while(temp->next!=NULL){
      insert_nosort(temp->next->element,temp->next->power);
      temp = temp->next;
      }
    mergesort();
    return(*this);
    }
}

    // ************************************ //
    // Overloaded Operator -=               //
    // ************************************ //
Complex_POLY& Complex_POLY::operator-=(const Complex_POLY& P)
{
  unsigned int p;
  Complex_POLY *RESULT;
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    RESULT = new Complex_POLY();
    return(*RESULT);
    }
  if(head!=NULL && P.head==NULL){
    //we subtract nothing, so return *this
    return(*this);
    }
  if(head==NULL && P.head!=NULL){
    //*this is NULL, so return -P
    *RESULT = P;
    Complex_POLY_CELL* temp;
    temp = RESULT->head;
    temp->element *= -1.0;
    while(temp->next!=NULL){
      temp->next->element *= -1.0;
      temp = temp->next;
      }
    return(*RESULT);
    }
  if(head!=NULL && P.head!=NULL){
    //both *this and P are non NULL
    Complex_POLY_CELL* temp;
    temp = P.head;
    insert(-1.0*temp->element,temp->power);
    while(temp->next!=NULL){
      insert(-1.0*temp->next->element,temp->next->power);
      temp = temp->next;
      }
    return(*this);
    }
}

The next two methods involve the multiplication of polynomials. The distinction between the * and the * = is as discussed above. In the *, we create a PRODUCT polynomial to store the result and then return it, while in the * =, we store the result in the this pointer to the left hand side and return that.

This code implements what might be called brute force multiplication. Consider the mathematics: given polynomials P and Q with representations


P(t) = $\displaystyle \sum_{j=0}^{N}$ aj tpj  
Q(t) = $\displaystyle \sum_{k=0}^{M}$ bk tqk  

The product of P and Q is given as


R(t) = $\displaystyle \sum_{j=0}^{N}$$\displaystyle \sum_{k=0}^{M}$ aj bk tpj + qk  
Q(t) = $\displaystyle \sum_{n=0}^{p_N+q_M}$$\displaystyle \sum_{(j,k): p_j+q_k = n}^{}$ ajbktn  

where the set {(j, k) : pj + qk = n} denotes the collection of (pj, qk) pairs which add up to a given power n. This set may be empty of course for some n, but this is a convenient notation. Note that this way of multiplying is of order P2 where P is the maximum of N and M, the degrees of the two polynomials. So this is not an efficient way to multiply polynomials for large degrees.

    // ************************************ //
    // Overloaded Operator *                //
    // ************************************ //
Complex_POLY Complex_POLY::operator*(const Complex_POLY& P)
{
  //cout << "entering overloaded * for P+Q" << endl;
  Complex_POLY* PRODUCT;
  PRODUCT = new Complex_POLY();
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    //cout << "Both this and incoming polynomial are degenerate" << endl;
    return(*PRODUCT);
    }
  if(head!=NULL && P.head==NULL){
    //we multiply nothing, so return NULL
    return(*PRODUCT);
    }
  if(head==NULL && P.head!=NULL){
    //*this is NULL, so return NULL
    return(*PRODUCT);
    }
  if(head!=NULL && P.head!=NULL){
    //both *this and P are non NULL
    //
    // *this          = \sum_{j=0}^n a_j t^{p_j}
    // P              = \sum_{k=0}^m b_k t^{q_k}
    // new polynomial = \sum_{n=0}^{p_n+q_m} c_n t^n
    // where c_n = \sum_(j,k) a_j b_k such that p_j+q_k = n
    //
    //cout << "Both polys are non null so we start the mulitplication" << endl;
    Complex_POLY_CELL* current = P.head;
    Complex_POLY_CELL* temp = head;
    while(temp!=NULL){  
      while(current!=NULL){
        PRODUCT->insert_nosort(current->element*temp->element,
                               current->power + temp->power);
        current = current->next;
        }
      current = P.head;
      temp = temp->next;
      }
    PRODUCT->mergesort();
    return(*PRODUCT);
    }
}

    // ************************************ //
    // Overloaded Operator *=               //
    // ************************************ //
Complex_POLY& Complex_POLY::operator*=(const Complex_POLY& P)
{
  Complex_POLY* PRODUCT;
  PRODUCT = new Complex_POLY();
  if(head==NULL && P.head==NULL){
    //both this and the incoming polynomial are degenerate
    return(*this);
    }
  else if(head!=NULL && P.head==NULL){
    //we multiply nothing, so return NULL
    return(*this);
    }
  else if(head==NULL && P.head!=NULL){
    //*this is NULL, so return NULL
    return(*this);
    }
  else{
    //both *this and P are non NULL
    Complex_POLY_CELL* current = P.head;
    Complex_POLY_CELL* temp = head;
    while(temp!=NULL){  
      while(current!=NULL){
        PRODUCT->insert_nosort(current->element*temp->element,
                               current->power + temp->power);
        current = current->next;
        }
      current = P.head;
      temp = temp->next;
      }
    PRODUCT->mergesort();
    *this = *PRODUCT;
    return(*this);
    }
}

This implements code to handle fragments of the sort

Complex_POLY S;
Complex t = 3.3 + 4.4*I;
//assume they have been built somehow
R *= t;

    // ********************************************* //
    // Overloaded Operator * (Complex_POLY,Complex)  //
    // ********************************************* //
Complex_POLY operator*(Complex_POLY& P,Complex t)
{
  Complex_POLY PRODUCT;
  Complex_POLY_CELL *T;
  if(P.head==NULL){
    //the incoming polynomial is degenerate
    return(PRODUCT);
    }
  else{
    //P is non NULL
    PRODUCT = P;
    for(ComplexPOLYIter next(PRODUCT); next;++next){
      *next() *= t;
      }
    return(PRODUCT);
    }
}

    // ************************************************ //
    // Overloaded Operator * (Complex, Complex_POLY)    //
    // ************************************************ //
Complex_POLY operator*(Complex t,Complex_POLY& P)
{
  Complex_POLY PRODUCT;
  Complex_POLY_CELL *T;
  if(P.head==NULL){
    //the incoming polynomial is degenerate
    return(PRODUCT);
    }
  else{
    //P is non NULL
    PRODUCT = P;
    for(ComplexPOLYIter next(PRODUCT); next;++next){
      *next() *= t;
      }
    return(PRODUCT);
    }
}

    // ********************************************** //
    // Overloaded Operator *= (Complex,Complex_POLY)  //
    // ********************************************** //
Complex_POLY& operator*=(Complex_POLY& P,Complex t)
{
  if(P.head==NULL){
    //the incoming polynomial is degenerate
    return(P);
    }
  else{
    //P is non NULL
    for(ComplexPOLYIter next(P); next;++next){
      *next() *= t;
      }
    return(P);
    }
}

\subsubsection{Evaluating  a Polynomial:}

\small
\begin{verbatim}
    // ***************************************** //
    //   Evaluation Function                     //
    // ***************************************** //
Complex Complex_POLY::operator()(Complex x)
{
  Complex value;
  int i;
  
  if(head==NULL){
    //this polynomial is degenerate
    value = 0.0;
    return(value);
    }
  else{
    //this is Non NULL
    Complex value = 0.0;
    Complex product = 1.0;
    Complex_POLY_CELL* temp = head;
    if(temp->next==NULL && temp->power==0){
      value = temp->element;
      return value;
      }
    if(temp->next==NULL && temp->power>0){
      product = 1;
      for(i=0;i<temp->power;++i)
        product *= x;
      return(product*temp->element);
      }
    value = temp->element;
    while(temp->next!=NULL){
      product = 1.0;
      for(i=0;i<temp->power-temp->next->power;++i)
        product *= x;
      value = (temp->next->element+value*product);
      temp = temp->next;
      }
    if(temp->power>0){
      product = 1.0;
      for(i = 0;i<temp->power;++i)
        product *= x;
      value *= product;
      return value;
      }
    return(value);
    }
}


next up previous contents
Next: Integration: Up: Implementation: The Complex_POLY_CELL Class: Previous: Mergesort:
Jim Peterson
1999-04-22