Following my question, I coded a simple tool to compute a root using the bisection method, which is working fine. Here is the code:
roots.h
#ifndef ROOTS_H
#define ROOTS_H
class FunctRoots {
public:
// default constructor
FunctRoots();
// destructor
virtual ~FunctRoots();
// return the error
virtual double evaluate(double x);
};
class Roots{
private:
double tol=1e-5;
int max_iter=100;
double a, b;
double fa=0.0;
double fb=0.0;
public:
// default constructor
Roots();
// destructor
virtual ~Roots();
// set tolerance
void set_tolerance(double tolerance);
// set the search space
void set_search_space(double a, double b);
// bracketing
void bracketing(FunctRoots& problem, double start, double step);
// bisection method
double bisection(FunctRoots& problem);
};
#endif
roots.cpp
#include "roots.h"
#include "iostream"
#include "cmath"
// define the template for the function
FunctRoots::FunctRoots () {}
FunctRoots::~FunctRoots () {}
double FunctRoots::evaluate(double x){
return 0.0;
};
// Roots class
Roots::Roots() {}
Roots::~Roots() {}
// set search space
void Roots::set_search_space(double a, double b){
this->a = a;
this->b = b;
}
// set tolerance
void Roots::set_tolerance(double tolerance){
this->tol = tolerance;
}
// bracketing
void Roots::bracketing(FunctRoots& problem, double start, double step){
// set initial boundary
this->a = start;
this->fa = problem.evaluate(this->a);
// main loop
this->b = start;
for (int iter = 0; iter < max_iter; iter++) {
// update upper boundary
this->b += step;
this->fb = problem.evaluate(this->b);
// check if a root exists
if (this->fa*this->fb < 0) break;
// update lower bound
this->a = this->b;
this->fa = this->fb;
}
// check boundaries
if (this->a > this->b){
double temp;
temp = this->a;
this->a = this->b;
this->b = temp;
temp = this->fa;
this->fa = this->fb;
this->fb = temp;
}
}
// bisection method
double Roots::bisection(FunctRoots& problem){
// variables declaration
double fx, x;
// compute errors
if (fabs(this->fa) < 1e-12){
this->fa = problem.evaluate(this->a);
}
// main loop
x = 0;
for (int iter = 0; iter < max_iter; iter++) {
// compute solution
x = (a+b)/2.0;
fx = problem.evaluate(x);
// print on screen
std::cout << "iter=" << iter << "\n";
std::cout << "a=" << a << "\n";
std::cout << "b=" << b << "\n";
std::cout << "x=" << x << "\n";
std::cout << "fx=" << fx << "\n\n";
// stop criterion
if (fabs(fx) < this->tol) break;
// update boundaries
if (this->fa*fx < 0){
this->b = x;
}else{
this->a = x;
this->fa = fx;
}
}
// function return
return x;
}
main.cpp
#include "roots.h"
#include "cmath"
class Problem: public FunctRoots{
private:
double value;
public:
Problem(double value){
this->value = value;
}
double evaluate(double x) {
return pow(cos(x),2)+this->value-x;
}
};
int main(){
Problem problem(6);
Roots roots;
//roots.set_search_space(5, 10);
roots.set_tolerance(1e-7);
roots.bracketing(problem, 0,0.1);
roots.bisection(problem);
return 0;
}
Now, the question is this: how can I make my main
looks like this?
int main(){
Problem problem(6);
Roots roots;
roots.set_problem(problem) // <----NEW
//roots.set_search_space(5, 10);
roots.set_tolerance(1e-7);
roots.bracketing(0,0.1); // <---- problem is not here anymore
roots.bisection(); // <---- problem is not here anymore
return 0;
}
Basically, I would like to define my problem once and for all just after initializing the solver so that I don't need to give it as input to the functions anymore, however considering that the function evaluate
is defined in FunctRoots
but then overridden in Problem
.