0
\$\begingroup\$

I'm looking for some assistance on an exercise for my C++ programming class. Unfortunately, I was rather ill the previous week an was unable to attend class, meaning I have only been able to use the textbook as a resource. I have done my best to complete the exercises, but, both because of my absence in class and my beginner status, I feel the code is rather flawed. I would really appreciate any corrections and suggestions, even moreso if you can elaborate on them.

Here are the instructions we were given for the assignment:

This assignment deals with representing and manipulating polynomials using simple arrays. A polynomial, such as anxn + an-1xn-1 + … + a0, will be implemented as an array of coefficients, with coefficient ai being stored in location i of the array. The coefficients are floating point values (potentially negative), so we will use an array of type double. The array will be dynamically allocated. This will allow us to represent very large polynomials and also allow us to increase the size of the array during execution if necessary.

The file Poly.h describes all the functions provided by the class.

You are to implement the following set of functions:

  • Default constructor that dynamically allocates an array of DEFAULTPOLY elements (set to 50) and constructs a polynomial value of 0.
  • A specialized (or alternate) constructor that takes an argument which indicates the size of the desired dynamic array and constructs a zero polynomial
  • A copy constructor
  • A destructor
  • An assignment operator
  • maxSize, which tells us the size of the currently allocated dynamic array
  • grow, to allocate a new, larger dynamic array and fill it with the existing data
  • setCoeff, to set a specific coefficient in the polynomial
  • `retrieveCoeff* to get a specific coefficient from the polynomial
  • *incrementCoeff`, to add a value to a specific coefficient in the polynomial
  • degree, which determines the degree of the polynomial
  • numOfTerms, which determines the number of terms in the polynomial (i.e., how many array elements are nonzero)
  • evaluate, which evaluates the polynomial for a given value of X
  • add, which adds one polynomial to another, changing the polynomial added to, growing the dynamic array if necessary
  • subtract, which subtracts one polynomial from another, changing the polynomial subtracted from, growing the dynamic array if necessary
  • derivative, which computes the derivative of a polynomial
  • equals, which determines the equality of two polynomials
  • `negate, which negates a polynomial
  • multByConst, which multiplies a polynomial by a constant value

Several functions are provided for you:

  1. A toString() function will be provided to you so that >all our polynomials will be displayed identically.
  2. The insertion operator is defined so we can easily print a polynomial
  3. The equality, inequality, and addition operators are provided and are simply defined in terms of your equals and add functions. You should not change any of the provided functions.

You will be supplied with one Poly.h file. The class declaration file Poly.h contains a complete specification of a class named Poly. Your task will be create the file Poly.cpp and to implement all the specified functions. Then you will need to create a PolyTest.cpp program to test your ADT.

Below is the the .h file we were provided with:

#ifndef POLY_H
#define POLY_H

#include <string>
using namespace std;


// default size of our dynamic coefficient array
const size_t DEFAULTPOLY = 50;    

class Poly
{

private:

  // Data members   [implementation of ADT's data object]
  // Feel free to change to meet your needs.

  size_t maxPoly;    // size of array
  double *coeff;     // dynamic array



public:

  // Default Class constructor
  // Allocate an array of DEFAULTPOLY elements and initializes it to the constant 0
  // post: Class object is initialized to degree-0 polynomial of 0  
  Poly ();

  // Non-default (alternate) Class constructor
  // Allocate an array of 'size' elements and initializes it to the constant 0
  // post: Class object is initialized to degree-0 polynomial of 0  
  Poly (size_t size);

  // Copy constructor
  // Construct a new Poly that is a copy of an existing Poly
  // post: Class object is initialized to be a copy of the argument Poly
  Poly (const Poly& aPoly);

  // Destructor
  // Destroy a poly object by freeing the dynamically allocated array
  ~Poly ();

  // Assignment operator
  // Assign rhs Poly object to 'this' Poly object
  const Poly& operator= (const Poly& rhs);



  // Member functions   [specs for ADT's operations]

  // maxSize
  // Return the size of the coefficient array
  size_t maxSize() const;


  // grow
  // This method will allow us to increase the size of the dynamically allocated
  // array by allocating a new array of the desired size, copying the data from
  // the old array to the new array, and then releasing the old array.
  // If the newSize is less than or equal to the current size, then no actions 
  // are taken.
  // Note: the maximum degree of a polynomial is one less than the size of the 
  // array. The parameter newSize represents the size of the array.
  void grow (size_t newSize);


  // degree
  // Finds the degree of a polynomial (the highest power with a
  //    non-zero coefficient)
  // pre: Class object exists
  // post: Returns the degree of the polynomial object.
  size_t degree () const;

  // setCoeff
  // Sets a term, value*x^i, in a polynomial, growing the array if necessary.
  // pre: Class object has been initialized. 0 <= i.
  // post: In the polynomial, the term with power i has coefficient
  //       value. The polynomical was grown if required.
  // Throws <std::out_of_range> if index i does not meet the precondition.
  void setCoeff (double value, size_t i);

  // retrieveCoeff
  // Finds the coefficient of the x^i term in poly
  // pre: Class object has been initialized. 0 <= i
  // post: Returns the value of the coefficient of the term with power i
  // note: If the object does not contain a term with power i (e.g., 
  //       i>=maxPoly), a coefficient value of zero is returned.
  // Throws <std::out_of_range> if index i does not meet the precondition.
  double retrieveCoeff (size_t i) const;

  // incrementCoeff
  // Changes a term, value*x^i, in a polynomial, growing the polynomial if required.
  // pre: Class object has been initialized. 0 <= i.
  // post: In the Class object the term with power i has its coefficient
  //       incremented by the given value. The array has grown if necessary.
  // Throws <std::out_of_range> if index i does not meet the precondition.
  void incrementCoeff (double value, size_t i);

  // toString  
  // Produce a string representation of a Poly object
  // pre: The class object has been initialized.
  // post: A string representation is returned.
  // dependencies: This function requires that the degree() and 
  //  retrieveCoeff() functions are implemented.
  // note: This function has been provided for you -- DO NOT CHANGE IT!
  string toString () const;

  // numOfTerms
  // Returns the number of terms in the polynomial.
  // pre: The class object has been initialized.
  // post: The number of non-zero terms of the polynomial is returned.
  size_t numOfTerms () const;

  // evaluate
  // Evaluate a polynomial for a specified value of X
  // pre: The class object has been initialized
  // post: The polynomial will be evaluated for the value of
  //       X received as an argument. The resulting value is
  //       returned.
  double evaluate (double x) const;

  // add
  // Add one polynomial to another
  // pre: The class object has been initialized. The received
  //       argument is also an initialized poly object.
  // post: The argument polynomial is added to the object polynomial.
  //       The object polynomial is changed to hold the sum. The object
  //       polynomial is grown if required to hold the resulting sum.
  // Note: the poly object being operated upon may be of a different
  //   size (maxPoly) than the aPoly parameter. If the aPoly parameter
  //   has a degree larger than the array in the 'this' Poly object,
  //   then the array is grown large enough to hold the sum.
  void add (const Poly& aPoly);

  // subtract
  // Subtract one polynomial from another
  // pre: The class object has been initialized. The received
  //       argument is also an initialized poly object.
  // post: The argument polynomial is subtracted from the object polynomial.
  //       The object polynomial is changed to hold the result. The object
  //       polynomial is grown if required to hold the result.
  // Note: the poly object being operated upon may be of a different
  //   size (maxPoly) than the aPoly parameter. If the aPoly parameter
  //   has a degree larger than the array in the 'this' Poly object,
  //   then the array is grown large enough to hold the result.
  void subtract (const Poly& aPoly);

  // addition operator
  // Add two polynomials together and return a new polynomial that is the result
  // pre: The class object has been initialized. The received
  //       argument is also an initialized poly object.
  // post: The argument polynomial is added to the object polynomial, and the
  //       result is stored in a new polynomial which is returned.
  //       The object polynomial is not changed.
  // note: This function has been provided for you -- DO NOT CHANGE IT!
  Poly operator+ (const Poly& rhs) const;

  // subtraction operator
  // Subtracts one polynomial from another and return a new polynomial that is the result
  // pre: The class object has been initialized. The received
  //       argument is also an initialized poly object.
  // post: The argument polynomial is subtracted from the object polynomial, and the
  //       result is stored in a new polynomial which is returned.
  //       The object polynomial is not changed.
  // note: This function has been provided for you -- DO NOT CHANGE IT!
  Poly operator- (const Poly& rhs) const;

  // equals
  // Determine if two polynomials are equal
  // pre: The class object has been initialized. The received
  //       argument is also an initialized poly object.
  // post: Returns true if the two polynomials are equal, false otherwise.
  bool equals (const Poly& aPoly) const;

  // Equality/inequality operators
  // note: These functions have been provided for you -- DO NOT CHANGE IT!
  bool operator== (const Poly& rhs) const;
  bool operator!= (const Poly& rhs) const;


  // negate
  // Negate a polynomial
  // pre: The class object has been initialized.
  // post: The polynomial has been changed to represent its
  //       multiplication by -1.0.
  void negate ();

  // multByConst
  // Multiply a polynomial by a constant
  // pre: The class object has been initialized.
  // post: The polynomial has been changed to represent its
  //       multiplication by the value of argument val.
  void multByConst (double val);

  // derivative
  // Compute the derivative of a polynomial
  // pre: The class object has been initialized.
  // post: The polynomial has been changed to represent its
  //       derivative.
  void derivative ();


  // insertion operator for output
  // note: This function has been provided for you -- DO NOT CHANGE IT!
  friend ostream& operator<< (ostream& os, const Poly &p);
#endif
};

An finally, here is the .cpp file I wrote:

#include <iostream>
#include <sstream>
#include <stdexcept>
#include <cmath>
#include "Poly.h"
using namespace std;


// Default Class constructor
// Allocate an array of DEFAULTPOLY elements and initializes it to the constant 0
// post: Class object is initialized to degree-0 polynomial of 0  
Poly::Poly()
{
    coeff = new double [DEFAULTPOLY];
    for (int i = 0; i < (int) DEFAULTPOLY; i++)
    {
        coeff[i] = 0.0;
    }
    maxPoly = DEFAULTPOLY;
}

// Non-default (alternate) Class constructor
// Allocate an array of 'size' elements and initializes it to the constant 0
// post: Class object is initialized to degree-0 polynomial of 0  
Poly::Poly(size_t size)
{
    coeff = new double[size];
    for (int i = 0; i < (int) size; i++)
    {
        coeff[i] = 0.0;
    }
    maxPoly = size;
}

// Copy constructor
// Construct a new Poly that is a copy of an existing Poly
// post: Class object is initialized to be a copy of the argument Poly
Poly::Poly(const Poly& aPoly)
{
    coeff = new double[aPoly.maxPoly];
    for (int i = 0; i < (int) aPoly.maxPoly; i++)
    {
        coeff[i] = aPoly.coeff[i];
    }
    maxPoly = aPoly.maxPoly;
}

// Destructor
// Destroy a poly object by freeing the dynamically allocated array
Poly::~Poly()
{
    delete[] coeff;
}

// Assignment operator
// Assign rhs Poly object to 'this' Poly object
const Poly& Poly::operator= (const Poly& rhs)
{
    if (this == &rhs){
        return *this;
    }
    Poly tmp(rhs);
    std::swap(maxPoly, tmp.maxPoly);
    std::swap(coeff, tmp.coeff);
    return *this;
}


//////////////////////////////////////////////////
//
// Member functions   [specs for ADT's operations]
//
//////////////////////////////////////////////////

// maxSize
// Return the size of the coefficient array
size_t Poly::maxSize() const
{
    size_t maxSize = maxPoly;
    return maxSize;
}

// grow
// This method will allow us to increase the size of the dynamically allocated
// array by allocating a new array of the desired size, copying the data from
// the old array to the new array, and then releasing the old array.
// If the newSize is less than or equal to the current size, then no actions 
// are taken.
// Note: the maximum degree of a polynomial is one less than the size of the 
// array. The parameter newSize represents the size of the array.
void Poly::grow(size_t newSize)
{
    int arrSize = (int) maxPoly;
    if ((int) newSize > arrSize)
    {
        double* newArrPtr = new double[newSize];
        for (int i = 0; i < arrSize; i++)
        {
            newArrPtr[i] = coeff[i];
        }
        std::swap(newArrPtr, coeff);
        std::swap(newSize, maxPoly);
    }

}

// degree
// Finds the degree of a polynomial (the highest power with a
//    non-zero coefficient)
// pre: Class object exists
// post: Returns the degree of the polynomial object.
size_t Poly::degree() const
{
    size_t degree = 0;
    for (int i = 0; i < (int)maxPoly; i++)
    {
        if (coeff[i] != 0)
        {
            degree = (size_t)i;
        }
    }
    return degree;
}


// setCoeff
// Sets a term, value*x^i, in a polynomial, growing the array if necessary.
// pre: Class object has been initialized. 0 <= i.
// post: In the polynomial, the term with power i has coefficient
//       value. The polynomical was grown if required.
// Throws <std::out_of_range> if index i does not meet the precondition.
void Poly::setCoeff(double value, size_t i)
{
    if ((size_t)0 <= i && i <= maxPoly)
    {
        if (i > maxPoly)
        {
            grow(i);
        }
        coeff[i] = value;
    }
    else
    {
        throw std::out_of_range("Index out of range");
    }
}

// retrieveCoeff
// Finds the coefficient of the x^i term in poly
// pre: Class object has been initialized. 0 <= i
// post: Returns the value of the coefficient of the term with power i
// note: If the object does not contain a term with power i (e.g., 
//       i>=maxPoly), a coefficient value of zero is returned.
// Throws <std::out_of_range> if index i does not meet the precondition.
double Poly::retrieveCoeff(size_t i) const
{
    if (0 <= (int)i)
    {
        return coeff[i];
    }
    else if (i >= (int)maxPoly)
    {
        return 0.0;
    }
    else
    {
        throw std::out_of_range("Index out of range");
    }
}

// incrementCoeff
// Changes a term, value*x^i, in a polynomial, growing the polynomial if required.
// pre: Class object has been initialized. 0 <= i.
// post: In the Class object the term with power i has its coefficient
//       incremented by the given value. The array has grown if necessary.
// Throws <std::out_of_range> if index i does not meet the precondition.
void Poly::incrementCoeff(double value, size_t i)
{
    if (0 <= (int)i)
    {
        if (i > (int)maxPoly)
        {
            grow(i);
        }
        coeff[i] *= value;
    }
    else
    {
        throw std::out_of_range("Index out of range");
    }

}

// toString  
// Produce a string representation of a Poly object
// pre: The class object has been initialized.
// post: A string representation is returned.
// dependencies: This function requires that the degree() and 
//  retrieveCoeff() functions are implemented.
// note: This function has been provided for you -- DO NOT CHANGE IT!
string Poly::toString() const
{
    ostringstream result;
    bool printedSomething = false;
    for (int i = (int)degree(); i >= 0; i--)
    {
        double c = retrieveCoeff(i);
        if (c != 0.0)
        {
            printedSomething = true;
            if (i == 0)
            {
                result.setf(ios::showpos);
                result << " " << c;
                result.unsetf(ios::showpos);
            }
            else
            {
                result.setf(ios::showpos);
                result << " " << c;
                result.unsetf(ios::showpos);
                result << "*X^" << i;
            }
        }
    }
    if (!printedSomething)
    {
        result.setf(ios::showpos);
        result << " " << 0;
        result.unsetf(ios::showpos);
    }
    return result.str();

}

// numOfTerms
// Returns the number of terms in the polynomial.
// pre: The class object has been initialized.
// post: The number of non-zero terms of the polynomial is returned.
size_t Poly::numOfTerms() const
{
    size_t numTerms = 0;
    for (int i = 0; i < (int)maxPoly; i++)
    {
        if (coeff[i] != 0)
        {
            numTerms++;
        }
    }
    return numTerms;
}

// evaluate
// Evaluate a polynomial for a specified value of X
// pre: The class object has been initialized
// post: The polynomial will be evaluated for the value of
//       X received as an argument. The resulting value is
//       returned.
double Poly::evaluate(double x) const
{
    double polyTotal = 0.0;
    double coeff = 0.0;
    for (int i = 0; i < (int) maxPoly; i++)
    {
        coeff = retrieveCoeff((size_t) i);
        polyTotal += (coeff * pow(x, (double)i));
    }
    return polyTotal;
}

// add
// Add one polynomial to another
// pre: The class object has been initialized. The received
//       argument is also an initialized poly object.
// post: The argument polynomial is added to the object polynomial.
//       The object polynomial is changed to hold the sum. The object
//       polynomial is grown if required to hold the resulting sum.
// Note: the poly object being operated upon may be of a different
//   size (maxPoly) than the aPoly parameter. If the aPoly parameter
//   has a degree larger than the array in the 'this' Poly object,
//   then the array is grown large enough to hold the sum.
void Poly::add(const Poly& aPoly)
{
    if (aPoly.maxPoly > maxPoly)
    {
        grow(aPoly.maxPoly);
    }
    for (int i = 0; i < (int)maxPoly; i++)
    {
        coeff[i] += aPoly.coeff[i];
    }
}

// subtract
// Subtract one polynomial from another
// pre: The class object has been initialized. The received
//       argument is also an initialized poly object.
// post: The argument polynomial is subtracted from the object polynomial.
//       The object polynomial is changed to hold the result. The object
//       polynomial is grown if required to hold the result.
// Note: the poly object being operated upon may be of a different
//   size (maxPoly) than the aPoly parameter. If the aPoly parameter
//   has a degree larger than the array in the 'this' Poly object,
//   then the array is grown large enough to hold the result.
void Poly::subtract(const Poly& aPoly)
{
    if (aPoly.maxPoly > maxPoly)
    {
        grow(aPoly.maxPoly);
    }
    for (int i = 0; i < (int) maxPoly; i++)
    {
        coeff[i] -= aPoly.coeff[i];
    }
}

// addition operator
// Add two polynomials together and return a new polynomial that is the result
// pre: The class object has been initialized. The received
//       argument is also an initialized poly object.
// post: The argument polynomial is added to the object polynomial, and the
//       result is stored in a new polynomial which is returned.
//       The object polynomial is not changed.
// note: This function has been provided for you -- DO NOT CHANGE IT!
Poly Poly::operator+ (const Poly& rhs) const
{
    Poly result;
    result.add(*this);
    result.add(rhs);
    return result;
}

// subtraction operator
// Subtracts one polynomial from another and return a new polynomial that is the result
// pre: The class object has been initialized. The received
//       argument is also an initialized poly object.
// post: The argument polynomial is subtracted from the object polynomial, and the
//       result is stored in a new polynomial which is returned.
//       The object polynomial is not changed.
// note: This function has been provided for you -- DO NOT CHANGE IT!
Poly Poly::operator- (const Poly& rhs) const
{
    Poly result;
    result.subtract(*this);
    result.subtract(rhs);
    return result;
}

// equals
// Determine if two polynomials are equal
// pre: The class object has been initialized. The received
//       argument is also an initialized poly object.
// post: Returns true if the two polynomials are equal, false otherwise.
bool Poly::equals(const Poly& aPoly) const
{
    if (maxPoly != aPoly.maxPoly)
    {
        return(false);
    }
    for (int i = 0; i < (int) maxPoly; i++)
    {
        if (aPoly.coeff[i] != coeff[i])
        {
            return(false);
        }
    }
    return(true);
}

// Equality/inequality operators
// note: These functions have been provided for you -- DO NOT CHANGE IT!
bool Poly::operator== (const Poly& rhs) const
{
    return equals(rhs);
}

bool Poly::operator!= (const Poly& rhs) const
{
    return !equals(rhs);
}


// negate
// Negate a polynomial
// pre: The class object has been initialized.
// post: The polynomial has been changed to represent its
//       multiplication by -1.0.
void Poly::negate()
{
    multByConst(-1.0);
}

// multByConst
// Multiply a polynomial by a constant
// pre: The class object has been initialized.
// post: The polynomial has been changed to represent its
//       multiplication by the value of argument val.
void Poly::multByConst(double val)
{
    double* tmpArray = new double[maxPoly];
    for (int i = 0; i < (int)maxPoly; i++)
    {
        tmpArray[i] = retrieveCoeff((size_t)i) * val;
    }
    std::swap(tmpArray, coeff);
}

// derivative
// Compute the derivative of a polynomial
// pre: The class object has been initialized.
// post: The polynomial has been changed to represent its
//       derivative.
void Poly::derivative()
{
    size_t derivArrSize = maxPoly - 1;
    double* derivArrPtr = new double[derivArrSize];
    for (int i = 1; i < (int) maxPoly; i++)
    {
        double coeffOfDeriv = retrieveCoeff((size_t)i) * (double)i;
        i -= 1;
        derivArrPtr[i] = coeffOfDeriv;
    }
    std::swap(derivArrPtr, coeff);
    std::swap(derivArrSize, maxPoly);
}

// insertion operator for output
// note: This function has been provided for you -- DO NOT CHANGE IT!
ostream & operator << (ostream &out, const Poly& p)
{
    out << p.toString();
    return out;
}

Please let me know what changes and improvements I can make. Additionally, if you have any suggestions for the testing of the Poly class, those would also be welcomed.

\$\endgroup\$

closed as off-topic by vnp, James Khoury, Kid Diamond, Edward, RubberDuck Sep 25 '14 at 11:48

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions containing broken code or asking for advice about code not yet written are off-topic, as the code is not ready for review. Such questions may be suitable for Stack Overflow or Programmers. After the question has been edited to contain working code, we will consider reopening it." – vnp, James Khoury, Kid Diamond, Edward, RubberDuck
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 2
    \$\begingroup\$ Are you allowed to use std::vector? \$\endgroup\$ – Corbin Sep 25 '14 at 3:03
  • \$\begingroup\$ @Corbin unfortunately, we have yet to cover that so I don't believe we can use it. \$\endgroup\$ – Nea Sep 25 '14 at 3:13
  • \$\begingroup\$ The code is broken. It doesn't even compile (line 416: tmpArray.maxPoly for example). Voting to close. \$\endgroup\$ – vnp Sep 25 '14 at 6:06
  • \$\begingroup\$ @vnp I have now fixed the code so that it complies. As I mentioned in the original post, I am a beginner and, thus, had trouble fixing the errors. You may notice that I acknowledged my .cpp has flaws and that those issues were part of the reason I needed help with review. I have since been reading other stackoverflow posts and have figured out how to fix the errors so that it compiles. However, the code still needs help. \$\endgroup\$ – Nea Sep 25 '14 at 6:25
  • 2
    \$\begingroup\$ @Nea If it doesn't compile You need to take it to StackOverflow. Then once you've fixed compilation issues & bugs bring it back here and we will help you in making your code look awesome. \$\endgroup\$ – James Khoury Sep 25 '14 at 7:49
2
\$\begingroup\$

Technically the code is still broken. Few observations anyway.

  • In-place modifiers (multByConstant, derivative) do not need a temporary array. You may modify coefficients directly, same way you do in add and subtract.

  • C-style casts almost always signal that something is wrong. In your case, using int for loop index is a bug: size_t may cover a larger span of values than int, which means that the int index would not be able to reach the whole array when maxPoly is large enough. Declare the index to be the same type as loop limits.

  • evaluate implementation is inefficient and numerically unsound. See Horner scheme for details.

  • To increment something one would add, not multiply (incrementCoeff)

  • derivative loop never terminates.

\$\endgroup\$

Not the answer you're looking for? Browse other questions tagged or ask your own question.