/* Numerical.h A C++ class for basic numerical calculations. ------------ Example usage for a function f(x). Numrical N; N.Diff(f, 5, 1) -> first derivative of f(x) at x=5. N.Ints(f, 1, 4) -> integral of f(x) at between 1 and 4. N.Root(f, 1) -> search for the root of f(x) around x=1 N.Opti(f, 1) -> search for the optimum value of f(x) around x=1 ------------ Contact : bingul(at)gantep.edu.tr ChangeLog 07.03.2014 The class is first written. 07.03.2014 Function-base methods are added. 11.03.2014 Array-base and vector-base methods are added. */ #ifndef NUMERICAL_H #define NUMERICAL_H 1 #include <cmath> #include <string> #include <vector> #include <iostream> using namespace std; /* **************************************************** */ class Numerical{ private: double tolerance, h; int maxiter; public: Numerical(); ~Numerical(); void Mess(string s); // Function-base methods double Intt(double (*fun)(double x), double a=0.0, double b=1.0, int n=1000); double Ints(double (*fun)(double x), double a=0.0, double b=1.0, int n=1000); double Diff(double (*fun)(double x), double x, int n=1); double Root(double (*fun)(double x), double x=1.0); double Opti(double (*fun)(double x), double x=1.0); // Array-base or vector-base methods double Diff(double x[], double y[], int size, int index, int n=1); double Intt(double x[], double y[], int size); double Intt(vector<double> x, vector<double> y); }; /* **************************************************** */ // ------------------------------------------------------------------------------- // The constructor function Numerical::Numerical(){ tolerance = 1.0e-6; h = 1.0e-3; maxiter = 50; } // ------------------------------------------------------------------------------- Numerical::~Numerical(){ // empty } // ------------------------------------------------------------------------------- // Prints a message void Numerical::Mess(string s){ cout << endl << "Numerical::Mess INFO \a" << s << endl; } /* Function-base methods */ // ------------------------------------------------------------------------------- // Retuns root of the function fun. x is the initial estimate. // Numerical method: Newton-Rapson double Numerical::Root(double (*fun)(double x), double x){ double err, xr = x; int iter=0; while(1){ err = fun(xr) / Diff(fun,xr,1); xr = xr - err; if(fabs(err)<tolerance) break; iter++; if(iter>maxiter) { Mess("Loop does not converge. You may change initial estimate."); break; } } return xr; } // ------------------------------------------------------------------------------- // Retunrs optimum value of the function fun. x is the initial estimate // Numerical method: Newton-Rapson double Numerical::Opti(double (*fun)(double x), double x) { double err, xo = x; int iter=0; while(1){ err = Diff(fun,xo,1) / Diff(fun,xo,2); xo = xo - err; if(fabs(err)<tolerance) break; iter++; if(iter>maxiter) { Mess("Loop does not converge. You may change initial estimate."); break; } } return xo; } // ------------------------------------------------------------------------------- // Returns first or second derivative of the function at point x. // Numerical method: Central Difference Appriximation double Numerical::Diff(double (*fun)(double x), double x, int n){ if(n<1 || n>2) { Mess("Order can be 1 or 2."); return 0.0; } if(n==1) return (fun(x+h)-fun(x-h))/(2.0*h); else return (fun(x+h)+fun(x-h)-2*fun(x))/(h*h); } // ------------------------------------------------------------------------------- // Returns integral of the function between a and b for n+1 equally-spaced points. // Numerical method: Trapezoidal method double Numerical::Intt(double (*fun)(double x), double a, double b, int n){ if(n<1) { Mess("n must be at least 1."); return 0.0; } double dx = (b-a)/n; double etf = (fun(a)+fun(b))/2; for (int i=1; i<n; i++){ etf += fun(a+i*dx); } return etf*dx; } // ------------------------------------------------------------------------------- // Returns integral of the function between a and b for n+1 equally-spaced points. // Numerical method: Simpson's method double Numerical::Ints(double (*fun)(double x), double a, double b, int n){ if(n<1 || n%2==1) { Mess("n must be at least 1 and even integer."); return 0.0; } double dx = (b-a)/n; double esf = fun(a)+fun(b); for (int i=1; i<=n-1; i++){ esf += 2.0 * pow(2.0,double(i%2)) * fun(a+i*dx); } return esf*dx/3.0; } /* Array-base or vector-base methods */ // ------------------------------------------------------------------------------- // Returns first or second derivative of array y of given size at given index. // Numerical method: Central Difference Appriximation double Numerical::Diff(double x[], double y[], int size, int index, int n){ if(n<1 || n>2) { Mess("Order can be 1 or 2."); return 0.0; } if(index<1 || index>size-2) { Mess("Index value is out of range."); return 0.0; } double dx = (x[index+1]-x[index-1])/2.0; if(n==1) return (y[index+1]-y[index-1])/(2.0*dx); else return (y[index+1]+y[index-1]-2*y[index])/(dx*dx); } // ------------------------------------------------------------------------------- // Returns integral of the array y of given size. // Numerical method: Trapezoidal method double Numerical::Intt(double x[], double y[], int size){ double etf = 0.0; for(int i=0; i<size-1; i++){ etf += 0.5 * (y[i+1]+y[i]) * (x[i+1]-x[i]); } return etf; } // ------------------------------------------------------------------------------- // Returns integral of the vector v. // Numerical method: Trapezoidal method double Numerical::Intt(vector<double> x, vector<double> y){ if(x.size()!=y.size()){ Mess("Size of vectors must be the same."); return 0.0; } double etf = 0.0; for(unsigned int i=0; i<y.size()-1; i++){ etf += 0.5 * (y[i+1]+y[i]) * (x[i+1]-x[i]); } return etf; } #endif