File: poly.cpp
#include <vector> #include <string> #include <cmath> #include "poly.h" using namespace std; /* * Remove leading zeros, but so as to empty the list. */ void Polynomial::normalize() { // Remove zeros from the end, except don't make the vector empty. while(m_coeff.size() > 1 && m_coeff.back() == 0.0) m_coeff.pop_back(); } /* * Evaluate at x. The trick is * 9x^5 + 8x^4 + 7x^3 + 5x^2 + 2x + 3 == * ((((((9)x + 8)x + 7)x + 5)x + 2)x + 3) * Each successive assignment of val is the value of a set of parentheses, * working from inside out. Initialize to highest coef (9 in the example), * then work through the other levels in the loop. For the example, the first * iteration will multiply 9 by x and add 8. The next multiplies that sum * by x again, and adds 7, etc. */ double Polynomial::f(double x) const { // Scan through the array _backwards_ (high order to low), computing // as indicated above. We initialize ret to the high coeff, then // loop through the others, multiplying x by the previous sum and // adding the coeff. vector<double>::const_reverse_iterator i = m_coeff.rbegin(); double val = *i++; for(; i != m_coeff.rend(); i++) { val = val * x + *i; } return val; } /* * Return the first derivative. */ Polynomial Polynomial::dx() const { vector<double> newvec; if(m_coeff.size() <= 1) { // Should never be 0. Using <= is paranoia. // If the poly is only a constant, df is 0. newvec.push_back(0.0); } else { // The reserve is for efficiency only. It makes sure the // object reserves all needed memory ahead of time, rather // than having to grow the storage as needed, guessing each // amount. It does not change the size, or any attribute // viewable through the public interface. This method still // works fine if the reserve call is removed. newvec.reserve(m_coeff.size()-1); // Push the coefficients on the new array. int exp = 1; for(auto i = m_coeff.begin() + 1; i != m_coeff.end(); ++i) newvec.push_back(*i * exp++); } // Return a Polynomial object containg the array we just built. return Polynomial(newvec); } /* * Return a string representation. */ string Polynomial::tos() const { string ret; // Accumulate return here. int exp = order(); // Exponent of the term. // This loop goes through the vector backwards (rbegin() and rend() // return reverse iterators), so from highest to lowest exponent. for(auto i = m_coeff.rbegin(); i != m_coeff.rend(); ++i, --exp) { // If the coefficient is zero, we skip it entirely. if(*i == 0.0) continue; // Get the coefficient, and clean up the format a bit. // If the coeff is 1.0, just represent it as the // empty string, unless it's the constant term. string coeff = ""; if(*i != 1.0 || exp == 0) { // Get the coefficient as a string (removing the sign). coeff = to_string(abs(*i)); // There are some shorter ways to do this, but // not that I want to explain just yet. This // is a good string exercise, though. If there // is a decimal place (we expect so), we strip // all trailing zeros, and the decimal point also // if it is the last after zero removal. if(coeff.find('.') != string::npos) { while(coeff.back() == '0') coeff.pop_back(); if(coeff.back() == '.') coeff.pop_back(); // Note: I can't run .back or .pop_back unless // I know the string isn't empty. But I do know // that, since it contains at least a decimal. // Otherwise, I would add a coeff.size() > 0 // test first. } } // Figure out what to put before the term. string before = ""; if(ret == "") { // This is the first term printed. Doesn't need // anything before it, but if it's negative, // we need to say so (we stripped the sign from // the coefficient string). if(*i < 0.0) before = "-"; } else { // Not the first. Put a + or - operator, based // on sign of the number. if(*i < 0.0) before = " - "; else before = " + "; } // Figure out what to put for the exponent part. // Only need them when larger than 1. string exppart = ""; if(exp > 1) exppart = "^"+to_string(exp); // And we need the variable, which we always call x, // except on the constant term. string var = "x"; if(exp == 0) var = ""; // Add this term to the result expression. ret += before + coeff + var + exppart; } // If all the terms were zero, we skipped them all. That // won't quite do. if(ret == "") ret = "0"; return ret; }

This file contains the bodies of larger methods from the the polynomial class Notice that when methods are defined here, they are physically located outside the class definition. For that reason, each method is prefixed by the class name, for instance Polynomial::normalize. This tells the compiler that the name belongs to the class, even though it's not inside it.

There is no hard and fast rule about which methods should stay inside the class definition and which should be moved to the .cpp file, but generally methods larger than one or two lines should be in .cpp.