/** File "Newton.cpp", by KWR for CSE250, Fall 2009. Problem Set 1(2) answer. Loosely based on http://www.daniweb.com/forums/thread154965.html, fixing its bugs. Test code in "main" and conversion to function-objects by KWR. "Const"---intended as final version, except that code for the PS2 answer will be added when its key is posted. USAGE: Since this now (11/30) includes the HiResTimer, it can only be compiled on timberlake, via g++ -O5 Newton.cpp -lrt NB: This file is NOT required for Problem Set 2, and no extra credit will be given fopr using it. I coded it because: () some students asked me about Newton's Method, and () "RealFn.h" is better for lecture notes than the example I'd previously prepared to use for pp303-306, which is part of a larger professional project of mine...which fails to build on some students' machines... Also illustrates working with "by-value" and "by-pointer" objects in the same code. The *objects* are the same, but both the modes of access and the virtual/non-virtual behavior can be different. */ #include #include #include // for fixed, setprecision #include "RealFn.h" #include "HiResTimer.h" using namespace Real; using std::cout; using std::endl; using std::fixed; using std::setprecision; class Newton { // an object that wraps a function to apply Newton's method const int maxIterations; const double error; const Real::MonicFn* f; const Real::MonicFn* fprime; public: Newton(const Real::MonicFn* f) : maxIterations(1000) , error(1.0e-6) , f(f) , fprime(f->dfdx()) { } /** Second constructor was debug help for Real::MonicFn::dfdx methods. It also allows other error tolerances and limits. */ Newton(const int maxIterations, const double error, const Real::MonicFn* f, const Real::MonicFn* fprime) : maxIterations(maxIterations) , error(error) , f(f) , fprime(fprime) { } /** Find root from starting point x---when x is greater than any root ** and inflection point **, this is "guaranteed" to find the largest root (except for really pathological functions!?). */ double findRootFrom(double x) { int n = 0; double xLast = x - 2.0*error; while ((std::abs(x - xLast) > error) && (n < maxIterations)) { xLast = x; //cout << n << ": " << xLast << endl; //debug only x -= ((*f)(x)/(*fprime)(x)); n++; } return x; } }; /** Problem Set 1 (2009), problem (2) answers---calculating n_0 for c = 2, 1.1. */ int main() { MonicFn* xx = new Times(new X(), new X()); MonicFn* xxx = new Times(xx, new X()); // Build f(x) = x^3 - 5x^2 - 20x + 10. MonicFn* p2 = new Plus(xxx, new Constant(10.0)); p2 = new Minus(p2, new Times(new Constant(5.0), xx)); p2 = new Minus(p2, new Times(new Constant(20.0), new X())); // Build x^3 - 50x^2 - 200x + 100 MonicFn* p11 = new Plus(xxx, new Constant(100.0)); p11 = new Minus(p11, new Times(new Constant(50.0), xx)); p11 = new Minus(p11, new Times(new Constant(200.0), new X())); // Build 40x(log x)^2 - (3x^2 + x). // Or rather, build 40(log x)^2 - 3x - 1 MonicFn* log2x = new Log(2.0,new X()); MonicFn* ps2 = new Times(new Constant(40.0), new Times(log2x,log2x)); ps2 = new Minus(new Minus(ps2, new Times(new Constant(3.0), new X())), new Constant(1.0) ); /** Problem Set 4 answers in Spring 2014 */ // Build 45x(log x)^2 - (3x^2 - x), which simplifies to // building 45(log x)^2 - 3x + 1. Note the "+ 1"! MonicFn* ps4 = new Times(new Constant(45.0), new Times(log2x,log2x)); ps4 = new Plus(new Minus(ps4, new Times(new Constant(3.0), new X())), new Constant(1.0) ); Newton newt2(p2); Newton newt11(p11); Newton newtps2(ps2); Newton newtps4(ps4); double start = 10000.0; double root2 = newt2.findRootFrom(start); double root11 = newt11.findRootFrom(start); double rootps2 = newtps2.findRootFrom(start); double rootps4 = newtps4.findRootFrom(start); cout << fixed << setprecision(6) << endl; cout << "Starting point for all three runs: x = " << start << endl; cout << endl; cout << "Fn for c = 2: " << p2->str() << endl; cout << "Assgt. 1 Problem (2) answer for c = 2: n_0 = least int above " << root2 << endl; cout << endl; cout << "Fn for c = 1.1: " << p11->str() << endl; cout << "Answer for c = 1.1: n_0 = least int above " << root11 << endl; cout << endl; //cout << "f11(54) = " << p11->operator()(54.0); //legal but verbose cout << "f11(53) = " << (*p11)(53.0) << endl; cout << "f11(54) = " << (*p11)(54.0) << endl; cout << "f11(" << root11 << ") = " << (*p11)(root11) << endl; cout << endl; cout << "Fn for PS2, problem (2): " << ps2->str() << endl; cout << "Tests of ps2: log2x(8.0) = " << (*log2x)(8.0) << endl; cout << "ps2(8.0) = " << (*ps2)(8.0) << endl; cout << endl; cout << "Assgt. 2 (2) answer: n_0 = least int above " << rootps2 << endl; cout << "Check: ps2(" << rootps2 << ") = " << (*ps2)(rootps2) << endl; cout << "ps2(1477) = " << (*ps2)(1477.0) << endl; cout << "ps2(1478) = " << (*ps2)(1478.0) << endl; double altStart = 100.0; cout << endl; cout << "Note, however, if you choose starting point x = " << altStart << ", you get:" << endl; double rootNaN = newtps2.findRootFrom(altStart); cout << "rootps2 = " << rootNaN << ", and weirdly, " << "ps2(" << rootNaN << ") = " << (*ps2)(rootNaN) << endl; cout << endl; cout << "Thus Newton's Method is not foolproof. Even centuries later \n" << "there is active research on improving it, including by Dr. Xu\n" << "and his students here at UB." << endl << endl; MonicFn* lhs = new Plus(xx, new Constant(3.0)); MonicFn* rhs = new Minus(log2x, new Constant(4.0)); MonicFn* prod = new Times(lhs,rhs); cout << endl; cout << "Parentheses example: " << prod->str() << endl; MonicFn* log2log2x = new Log(2.0, log2x); MonicFn* weirdExponent = new Div(log2x, log2log2x); MonicFn* powExample = new Pow(log2x, weirdExponent); cout << "Value of " << powExample->str() << " for x = 3 is " << (*powExample)(3.0) << endl; cout << "Derivative is " << powExample->dfdx()->str() << endl; cout << "Value of derivative at x = " << 7 << " is " << (*powExample->dfdx())(7.0) << endl; HiResTimer timer; MonicFn* lnx = new Ln(new X()); MonicFn* lnlnx = new Ln(lnx); MonicFn* weirdExponent2 = new Div(lnx, lnlnx); MonicFn* powExample2 = new Pow(lnx, weirdExponent2); MonicFn* powExample2B = new PowB(lnx, weirdExponent2); cout << "Value of " << powExample2->str() << " for x = 3 is " << (*powExample2)(3.0) << endl; MonicFn* derivLazy; MonicFn* derivExplicit; double timeLazy; double timeExplicit; timer.reset(); derivLazy = powExample2->dfdx(); timeLazy = timer.elapsedTime(); derivExplicit = powExample2B->dfdx(); timeExplicit = timer.elapsedTime(); double sumTime = timer.timeSinceReset(); cout << "Lazy derivative is " << derivLazy->str() << endl; cout << "Expl derivative is " << derivExplicit->str() << endl; cout << "Times in " << timer.getUnits() << "---Lazy: " << timeLazy << ", Explicit: " << timeExplicit << endl; cout << "Value of derivative at x = " << 7 << " is " << (*powExample2->dfdx())(7.0) << endl; cout << endl << "And now what we've all been waiting for: the highest root" << endl << "in Problem Set 4(2) is " << rootps4 << endl; int n0val = trunc(rootps4 + 0.99999); cout << "For the next-higher integer this means (alas) " << n0val << endl; return(0); }