C++ function inside function - c++

/*I need to use the result from the (delta) function inside the (sol_ec_II) function for a school assignment.*/
#include <iostream>
#include <ctgmath>
using namespace std;
double delta(double a, double b, double c) {
return (b * b) - (4 * a * c);/* so I need to take this value [(b * b) - (4 * a * c)]
and use it in sol_ec_II in the places where I wrote "delta". */
}
void sol_ec_II(double a, double b, double c) {
if (delta < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
// I would also need to use the (delta) function inside the (sol_ec_II) so they use the same
a, b, c values like this:
void sol_ec_II(double a, double b, double c) {
delta(a, b, c);
if (delta < 0) {
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);
double x2 = -1 * b + sqrt(delta);
}
}
//so I don't understand how to get the value that results from delta(a, b, c) and use it inside the if statement and sqrt.

The result "comes out" of the function call at the time you call it. Look, you already know how sqrt works. sqrt is a function! You write sqrt(something) and that calls the function sqrt and it calls the function sqrt with the argument something and then the return value from sqrt gets used in the place where you wrote sqrt(something). e.g. 1 + sqrt(4) calculates 3.
Likewise the return value from delta gets used in the place where you wrote delta(a, b, c). If you want to call delta and then call sqrt (i.e. calculate the square root of the delta) you write sqrt(delta(a, b, c)).
Obviously, just calculating a number is pretty useless. You probably want to do something with the number, like saving it in a variable or printing it. Examples:
cout << "the square root of the delta is " << sqrt(delta(a,b,c)) << endl;
cout << "the delta plus one is " << (delta(a,b,c) + 1) << endl;
double the_delta = delta(a,b,c);
cout << "the delta is " << the_delta << " and the square root of the delta is " << sqrt(the_delta) << endl;
if (delta(a,b,c) < 0)
cout << "the delta is negative" << endl;
else
cout << "the delta isn't negative" << endl;
Note: Every time the computer runs delta(a,b,c) it calls the delta function. It doesn't remember the calculation from last time. You can see this because if you put cout instructions inside the delta function, they get printed every time the computer runs delta(a,b,c).
Of course I will not give you the solution for your program. I hope this helps you understand how functions work.

here you should pass parameters to deleta function in order to execute it:
void sol_ec_II(double a, double b, double c) {
if (delta(a,b,c) < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
or you could save the result in a new variable called result for example, and after that use it, like that:
void sol_ec_II(double a, double b, double c) {
double result = delta(a,b,c);
if (result < 0) {//here
cout << endl << "Polinomul NU are solutii.";
}
else {
double x1 = -1 * b - sqrt(delta);//here
double x2 = -1 * b + sqrt(delta);//here
}
}
The Same thing for the second function, always to execute a function use parenthesis and pass between them the arguments that the function expects.

To reuse the value you get from calling a function multiple time use a variable:
double delta(double,double,double) { return 1.2; /*ignore this for now*/ }
void sol_ec_II(double a, double b, double c) {
const auto kDelta = delta(a, b, c);
if (kDelta < 0.0) {
// do stuff
} else {
const auto kRootD = sqrt(kDelta); // same idea
const auto x1 = -b - kRootD;
const auto x2 = -b + kRootD;
// use the variables
}
}
I use auto out of habit, you don't need to, double is fine.

Related

How can I get a function to read the next line of a document everytime it's called?

Really new programmer with a really bad professor here.
I have this code that is supposed to get inputs from a text document (inputsFile) using a function (get_coefficients) and do stuff with it. Currently, everything works perfectly except it reads the same line from the file every time it's executed in the while loop in main. I've google around but I can't find anything that is implementable in my case. I've tried implementing while loops and trying to pass some sort of counting variable but nothing seems to work.
Since this is an assignment for school, I can't do anything fancy. So the more elementary the explanation, the better please, haha. Thank you in advance for any help I get.
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
//=======================================FUNCTIONS======================================
//a function that displays instructions
void display_instructions() {
cout << "Enter a, b, c: ";
}
//a function that gathers inputs
void get_coefficients(double& a, double& b, double& c) {
ifstream inputsFile;
string inputs;
string inputString;
inputsFile.open("textinputs.txt");
inputsFile >> a >> b >> c;
cout << a << b << c;
inputsFile.close();
}
//a function that calculates a discriminant
double calc_discriminant(double a, double b, double c) {
double discriminant = (b * b) - (4 * a * c);
return discriminant;
}
//a function that calculates root 1
double calc_root_1(double a, double b, double c, double disc) {
double r1 = ((-b) + (sqrt(disc))) / (2 * a);
return r1;
}
//a function that calculates root 2
double calc_root_2(double a, double b, double c, double disc) {
double r2 = ((-b) - (sqrt(disc))) / (2.0 * a);
return r2;
}
void display(double r1, double r2) {
cout << "the roots are " << r1 << " and " << r2 << "." << endl;
}
//=======================================EXCECUTE=======================================
int main()
{
//while again is true
for (int i = 0; i < 3; i++) {
double a, b, c;
display_instructions();
//run get numbers
get_coefficients(a, b, c);
//if discrimant less than 0 stop the program
if (calc_discriminant(a, b, c) < 0) {
cout << "No real solution" << endl;
}
else { //else get the roots
double disc = calc_discriminant(a, b, c);
double r1 = calc_root_1(a, b, c, disc);
double r2 = calc_root_2(a, b, c, disc);
//print the roots
display(r1, r2);
}
}
}
The problem here is that when you do inputsFile.open() you're opening the file from the start. You should only open the file once so each time you read from it you'll read the next line from where you were the last time. However, the ifstream will be deleted at the end of the scope if you don't save it anywhere. What you can do is initialize the ifstream in main() and then pass it to the function by reference so the ifstream will still be there until the program reaches the end of main.
I think this should work for what you want:
#include <iostream>
#include <fstream>
#include <string>
#include <math.h>
using namespace std;
//=======================================FUNCTIONS======================================
//a function that displays instructions
void display_instructions() {
cout << "Enter a, b, c: ";
}
//a function that gathers inputs
void get_coefficients(double& a, double& b, double& c, ifstream& inputsFile) {
string inputs;
string inputString;
inputsFile >> a >> b >> c;
cout << a << b << c;
}
//a function that calculates a discriminant
double calc_discriminant(double a, double b, double c) {
double discriminant = (b * b) - (4 * a * c);
return discriminant;
}
//a function that calculates root 1
double calc_root_1(double a, double b, double c, double disc) {
double r1 = ((-b) + (sqrt(disc))) / (2 * a);
return r1;
}
//a function that calculates root 2
double calc_root_2(double a, double b, double c, double disc) {
double r2 = ((-b) - (sqrt(disc))) / (2.0 * a);
return r2;
}
void display(double r1, double r2) {
cout << "the roots are " << r1 << " and " << r2 << "." << endl;
}
//=======================================EXCECUTE=======================================
int main()
{
ifstream inputsFile;
inputsFile.open("textinputs.txt");
//while again is true
for (int i = 0; i < 3; i++) {
double a, b, c;
display_instructions();
//run get numbers
get_coefficients(a, b, c, inputsFile);
//if discrimant less than 0 stop the program
if (calc_discriminant(a, b, c) < 0) {
cout << "No real solution" << endl;
}
else { //else get the roots
double disc = calc_discriminant(a, b, c);
double r1 = calc_root_1(a, b, c, disc);
double r2 = calc_root_2(a, b, c, disc);
//print the roots
display(r1, r2);
}
}
inputsFile.close();
}

Cube root of a number, C++

I would like to ask a very short question, and it is as follows: in finding the cube root of a number (both neg. and pos.) in C++, how does one restrict the output to real solutions only?
I am currently writing a program to solve a cubic with Cardano's formula, and one of the intermediate variables I am using randomly outputs the complex and real cube roots - and I only need the real roots.
(E.g. in evaluating the cube root of -0.0127378, the three roots would be 0.11677095+0.202253218i, −0.2335419, 0.11677095−0.202253218i - I wish to ignore the complex ones for substitution into a later formula)
Thank you!
EDIT: Solved it! :) I created a signum function and tweaked the sign after taking the power of the absolute value of SPrime and TPrime, so now it carries forward only the real cube root.
/* ... */
#include <iostream>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cassert>
using namespace std;
int signum(std::complex<double> z)
{
if (z.real() < 0 || z.imag() < 0) return -1;
else if (z.real() >= 0 || z.imag() >= 0) return 1;
}
// POST: The function is intended to solve a cubic equation with coefficients a, b, c and d., such that
// ax^3 + bx^2 + cx + d = 0. If there exist infinitely many solutions, we output -1, i.e. if a=b=c=d=0
// (trivial solution).
void solve(std::complex<double> a, std::complex<double> b, std::complex<double> c, std::complex<double> d, std::complex<double>& x1, std::complex<double>& x2, std::complex<double>& x3)
{
complex<double> i = complex<double> (0, 1.0);
// Consider implementing Cardano's method for obtaining the solution of a degree 3 polynomial, as suggested
// We must hence define the discriminant D of such an equation through complex doubles Q and R
std::complex<double> Q;
Q = (3.0*a*c - pow(b, 2)) / (9.0*pow(a, 2));
cout << "Q=" << Q << endl;
std::complex<double> R;
R = (9.0*a*b*c - 27.0*d*pow(a, 2) - 2.0*pow(b, 3)) / (54.0*pow(a, 3));
cout << "R=" << R << endl;
std::complex<double> D;
D = pow(Q, 3) + pow(R, 2);
// Possible types of output for discriminant
if (abs(D) < 0.0)
{
cout << "The cubic has three distinct, real roots." << endl;
}
else if (abs(D) == 0.0)
{
cout << "The cubic has three real roots, at least two of which are equal." << endl;
}
else if (abs(D) > 0.0)
{
cout << "The cubic has one real root and two complex conjugate roots." << endl;
}
// Defining two further complex double variables S and T, which are required to obtain the final solution for x1, x2 and x3
std::complex<double> S;
std::complex<double> SPrime;
SPrime = R+sqrt(Q*Q*Q + R*R);
cout << "SPrime=" << SPrime << endl;
if (signum(SPrime) == -1)
{
S = (-1)*pow(abs(SPrime), 0.3333333333333);
}
else if (signum(SPrime) == 1)
{
S = pow(abs(SPrime), 0.3333333333333);
}
cout << "S=" << S << endl;
std::complex<double> T;
std::complex<double> TPrime;
TPrime = (R-sqrt(Q*Q*Q + R*R));
if (signum(TPrime) == -1)
{
T = (-1)*pow(abs(TPrime), 0.3333333333333);
}
else if (signum(TPrime) == 1)
{
T = pow(abs(TPrime), 0.3333333333333);
}
cout << "T=" << T << endl;
cout << "TPrime= " << TPrime << endl;
// Expressions for the solutions
x1 = S + T - (b/(3.0*a));
x2 = (-0.5)*(S + T) - (b/(3.0*a)) + (sqrt(3.0)*0.5)*(S - T)*i;
x3 = conj(x2);
if (abs(x1) < 0.000000000001)
{
x1 = 0;
}
}
// Driver code
int main ()
{
// Taking user input for a, b, c and d
std::complex<double> a, b, c, d, x1, x2, x3;
cout << "Please enter the coefficients of the polynomial in successive order." << endl;
cin >> a >> b >> c >> d;
solve (a, b, c, d, x1, x2, x3);
cout << x1 << ", " << x2 << ", " << x3 << "." << endl;
return 0;
}
The problem as you're stating it can be solved trivially (with real numbers the cubic root of -x is the opposite of the cubic root of x):
double cuberoot(double x) {
if (x < 0) {
return -pow(-x, 1.0/3.0);
} else if (x > 0) {
return pow(x, 1.0/3.0);
} else {
return 0;
}
}
If the input is instead in general complex z and you're looking for the "most real" (principal) cubic root the same reasoning can be applied using complex pow version to either z or -z depending on the sign of the real part:
std::complex<double> cuberoot(std::complex<double> z) {
if (z.real() < 0) {
return -pow(-z, 1.0/3.0);
} else {
return pow(z, 1.0/3.0);
}
}
Problems with your code:
As you allow complex coefficients, the discussion of the discriminant becomes slightly meaningless, it is only of value for real coefficients.
abs(D) is always non-negative. If D==0, then there is a double root, more can not be said in the case of complex coefficients.
You can avoid a lot of code by utilizing that S*T=-Q. One would have to care that the computation of u=T^3 returns the larger of the roots of 0==u^2 - 2*R*u - Q^3 or (u-R)^2 = D = R^2+Q^3
rtD = sqrt(D);
T = cuberoot( R + (abs(R+rtD)>=abs(R-rtD)) ? rtD : -rtD );
S = (abs(T)<epsilon) ? 0 : -Q/T;
Because of abs(R)<=abs(T)^3 and abs(D)<=abs(T)^6
one gets also abs(Q)<=2^(1/3)*abs(T)^2 resulting in
abs(S)=abs(Q/T) <= 2^(1/3)*abs(T)
For S=-Q/T to fail one would thus need a serious case
of extremely small floating point numbers in R, Q
and thus T. Quantitatively, for double even
the threshold epsilon=1e-150 should be safe.
On cube root variants:
For esthetic reasons one might want T as close to a coordinate axis as possible. A cube root function achieving this would be
std::complex<double> cuberoot(std::complex<double> z) {
double r=abs(z), phi=arg(z);
double k = round(2*phi/pi);
// closest multiple of pi/2
// an equivalent angle is (phi-k*pi/2) - k*3*pi/2
return std::polar( pow(r,1.0/3), (phi-k*pi/2)/3 - k*pi/2 );
}
so that abs(phi-k*pi/2)<=pi/4, and thus the angle to the next coordinate axis of the cube root is smaller than pi/12=15°. cuberoot(i) returns -i, cuberoot(-1) returns -1, a point at 60° returns a cube root at (60°-90°)/3-90°=-100°, etc.

How do I properly pass these function values in C++

I am trying to write a program using functions that calculates county tax, sales tax, adds them together, and outputs them in main. I have also made a printData function so I could output everything at once but i'm confused on how to use it, because of an initialization error in run time. I am not very good with function and was hoping I could get some help.
Here is my written code: (updated)
#include <iostream>
using namespace std;
void calcCounty(double &TotalSales, double &CountySalesTax);
void calcState(double &TotalSales, double &StateSalesTax);
void calcTotal(double &TotalSales, double &CountySalesTax, double &StateSalesTax);
void printData(double &TotalSales, double &CountySalesTax, double &StateSalesTax);
double TotalSales;
double CountySalesTax;
double StateSalesTax;
int main()
{
cout << "Tax Calculation program" << endl;
cin >> TotalSales;
printData(TotalSales, CountySalesTax, StateSalesTax);
cout << TotalSales << CountySalesTax << StateSalesTax;
return 0;
}
void calcCounty(double &TotalSales, double &CountySalesTax)
{
CountySalesTax = TotalSales * 0.4;
}
void calcState(double &TotalSales, double &StateSalesTax)
{
StateSalesTax = TotalSales * 0.2;
}
void calcTotal(double &TotalSales, double &CountySalesTax, double &StateSalesTax)
{
TotalSales = CountySalesTax + StateSalesTax;
}
void printData(double &TotalSales, double &CountySalesTax, double &StateSalesTax)
{
cout << TotalSales, CountySalesTax, StateSalesTax;
}
Why don't you rather return a value from your functions?
double calcCounty(double& totalSales) {
return totalSales * 0.4;
}
Then in your main do:
countySalesTax = calcCounty(totalSales);
You need to initialize your variables first (the ones you need).
For example, this function:
void calcCounty(double &TotalSales, double &CountySalesTax)
{
CountySalesTax = TotalSales * 0.4;
}
should have TotalSales initialized before been called.
As suggested by the comments, you also need to call the functions at some point.
Moreover, the printing should be done like this in your case:
cout << TotalSales << ", " << CountySalesTax << ", " << StateSalesTax;
First, I would suggest you to read this example:
#include <iostream>
using namespace std;
/*
* Write a program, which will declare two variables, 'a' and 'b'.
* They will be initialized with the values 10 and 100, respectively.
* Write a function 'int find_min(int a, int b)`, which will find
* which of the given parameters is less and will return it.
*
* Then, write `void find_min_no_return(int a, int b, int& min)`,
* which will do the same job as `find_min()`, but with no return
* statement.
*/
int find_min(int a, int b) {
if(a < b) {
return a;
}
else {
return b;
}
}
/*
* 'min' is passed by reference because it is
* going to be modified. 'a' and 'b' are passed
* by value.
*/
void find_min_no_return(int a, int b, int& min) {
if(a < b) {
min = a;
}
else {
min = b;
}
}
int main() {
int a = 10;
int b = 100;
int min;
min = find_min(a, b);
cout << "min of first function called = " << min << endl;
find_min_no_return(a, b, min);
cout << "min of second function called = " << min << endl;
return 0;
}
and then solve your problem.

c++ gsl interaction between objects in ode

Would you please help me with my problem. I'm trying to write a program where objects in different class interact. I base my model on the gsl library to resolve my ordinary differential equations (ode).
Instances of different classes consume each other, so they get or loose mass when they eat or are eaten.
My 2 ode are like b[i] = sum of consumption - sum of consumed. I calculate consumption as follow, with 1 being the consumer and 0, the prey.
conso[1] = y[0] * x[1] * y[1]
The original code comes from "sample code using gsl routines" as follow with modifications. The instances of class A and B are included in maps of class C.
I'm new to c++ and I don't see how I can integrate a loop in the ode to make it calculate what has been consumed by each instance, and remove it from the other instances that have been eaten. The best would be to use functions and variables that are in the istances class but the function where the ode are has to be static. I thought about array but it seems that arrays can't be parameters of the odes.
The other problem is that for each instance, the parameters has to change and be taken in the class, but how I did here, in the loop with the iterators, the ode will work for the last instance... Again I would have like to use an array of class C that take the parameter of the instances in class A and B, but because the function is static I can't use the array of the class "C". I'm in real trouble !
Do you have any ideas ? Thank you !
// include files
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv.h>
// ************************* C.h ****************************
class C
{
public :
C(std::map(std::map<std::string,A> &A, std::map<std::string,B> &B);
~C();
int integ(void);
int static rhs (double t, const double y[], double f[], void *params_ptr);
private :
std::map<std::string,A> &A,
std::map<std::string,B> &B,
};
//*************************** C.cpp ****************************
int C::integ (void)
{
int dimension = 2; // number of differential equations
double eps_abs = 1.e-8; // absolute error requested
double eps_rel = 1.e-10; // relative error requested
// define the type of routine for making steps:
const gsl_odeiv_step_type *type_ptr = gsl_odeiv_step_rkf45;
// allocate/initialize the stepper, the control function, and the
// evolution function.
gsl_odeiv_step *step_ptr = gsl_odeiv_step_alloc (type_ptr, dimension);
gsl_odeiv_control *control_ptr = gsl_odeiv_control_y_new (eps_abs, eps_rel);
gsl_odeiv_evolve *evolve_ptr = gsl_odeiv_evolve_alloc (dimension);
gsl_odeiv_system my_system; // structure with the rhs function, etc.
// parameter for the diffeq
for(itA=A.begin(); itA!=A.end(); ++itA)
{
x = itA->second.getx();
my_system.params = &x; // parameters to pass to rhs
}
for(itB=B.begin(); itB!=B.end(); ++itB)
{
z = itB->second.getz();
my_system.params = &z; // parameters to pass to rhs
}
double y[2]; // current solution vector
double t, t_next; // current and next independent variable
double tmin, tmax, delta_t; // range of t and step size for output
double h = 1e-6; // starting step size for ode solver
// load values into the my_system structure
my_system.function = rhs; // the right-hand-side functions dy[i]/dt
my_system.dimension = dimension; // number of diffeq's
tmin = 0.; // starting t value
tmax = 100.; // final t value
delta_t = 1.;
for(itA=A.begin(); itA!=A.end(); ++itA)
{
y[0] = itA->second.getY(); // initial y value
}
for(itB=B.begin(); itB!=B.end(); ++itB)
{
y[1] = itB->second.getY(); // initial y value
}
t = tmin; // initialize t
// print initial values
cout << scientific << setprecision (5) << setw (12) << t << " "
<< setw (12) << y[0] << " " << setw (12) << y[1] << endl;
// step to tmax from tmin
for (t_next = tmin + delta_t; t_next <= tmax; t_next += delta_t)
{
while (t < t_next) // evolve from t to t_next
{
gsl_odeiv_evolve_apply (evolve_ptr, control_ptr, step_ptr,
&my_system, &t, t_next, &h, y);
}
// print at t = t_next
cout << scientific << setprecision (5) << setw (12) << t << " "
<< setw (12) << y[0] << " " << setw (12) << y[1] << endl;
}
// all done; free up the gsl_odeiv stuff
gsl_odeiv_evolve_free (evolve_ptr);
gsl_odeiv_control_free (control_ptr);
gsl_odeiv_step_free (step_ptr);
return 0;
}
//*************************** rhs ****************************
int C :: rhs (double , const double y[], double f[], void *params_ptr)
{
// get parameter(s) from params_ptr; here, just a double
double x = *(double *) params_ptr;
double z = *(double *) params_ptr;
// evaluate the right-hand-side functions at t
f[1] = x * y[1] + sum consumption - sum consumed; //objects of class A
f[0] = - z * y[0] - sum consumed; //objects of class B
return GSL_SUCCESS; // GSL_SUCCESS defined in gsl/errno.h as 0
}
I tried to add consumption, but it says "error: 'void' must be the first and only parameter if
specified" :
int C :: rhs (double , const double y[], double f[], void *params_ptr, void conso)
{
// get parameter(s) from params_ptr; here, just a double
double x = *(double *) params_ptr;
double z = *(double *) params_ptr;
// evaluate the right-hand-side functions at t
f[0] = z * y[0]; //objects of class A
f[1] = - x * y[1] + conso; //objects of class B
return GSL_SUCCESS; // GSL_SUCCESS defined in gsl/errno.h as 0
}
//***And in int C :: integ :
for(itA=A.begin(); itA!=A.end(); ++itA)
{
for(itB=B.begin(); itB!=B.end(); ++itB)
{
void conso = itA->second.conso(itB->second, x);
}
}
//***With in class A :
void A :: conso(Group &prey, double x)
{
double conso=0;
conso = x * y * prey.gety();
}

Adaptive Quadrature (C++)

I'm having issues with my adaptive trapezoidal rule algorithm in C++ -- basically, regardless of the tolerance specified, I get the same exact approximation. The recursion is supposed to stop very early for large tolerances (since abs(coarse-fine) is going to be smaller than 3.0*large tolerance and minLevel of recursion is about 5).
However, what this function does is run the maximum number of times regardless of choice of tolerance. Where did I mess up?
EDIT: Perhaps there are issues in my helper functions?
double trap_rule(double a, double b, double (*f)(double),double tolerance, int count)
{
double coarse = coarse_helper(a,b, f); //getting the coarse and fine approximations from the helper functions
double fine = fine_helper(a,b,f);
if ((abs(coarse - fine) <= 3.0*tolerance) && (count >= minLevel))
//return fine if |c-f| <3*tol, (fine is "good") and if count above
//required minimum level
{
return fine;
}
else if (count >= maxLevel)
//maxLevel is the maximum number of recursion we can go through
{
return fine;
}
else
{
//if none of these conditions are satisfied, split [a,b] into [a,c] and [c,b] performing trap_rule
//on these intervals -- using recursion to adaptively approach a tolerable |coarse-fine| level
//here, (a+b)/2 = c
++count;
return (trap_rule(a, (a+b)/2.0, f, tolerance/2.0, count) + trap_rule((a+b)/2.0, b, f, tolerance/2.0, count));
}
}
EDIT: Helper and test functions:
//test function
double function_1(double a)
{
return pow(a,2);
}
//"true" integral for comparison and tolerances
//helper functions
double coarse_helper(double a, double b, double (*f)(double))
{
return 0.5*(b - a)*(f(a) + f(b)); //by definition of coarse approx
}
double fine_helper(double a, double b, double (*f)(double))
{
double c = (a+b)/2.0;
return 0.25*(b - a)*(f(a) + 2*f(c) + f(b)); //by definition of fine approx
}
double helper(double a, double b, double (*f)(double x), double tol)
{
return trap_rule(a, b, f, tol, 1);
}
And here's what's in main():
std::cout << "First we approximate the integral of f(x) = x^2 on [0,2]" << std::endl;
std::cout << "Enter a: ";
std::cin >> a;
std::cout << "Enter b: ";
std::cin >> b;
true_value1 = analytic_first(a,b);
for (int i = 0; i<=8; i++)
{
result1 [i] = helper(a, b, function_1, tolerance[i]);
error1 [i] = fabs(true_value1 - result1 [i]);
}
std::cout << "(Approximate integral of x^2, tolerance, error )" << std::endl;
for (int i = 0; i<=8; i++)
{
std::cout << "(" << result1 [i] << "," << tolerance[i] << "," << error1[i] << ")" << std::endl;
}
I find that exactly the opposite of what you suggest is happening --- the algorithm is terminating after only minLevel steps --- and the reason is due to your usage of abs, rather than fabs in the tolerance test. The abs is converting its argument to an int and thus any error less than 1 is getting rounded to zero.
With the abs in place I get this output from a very similar program:
(0.333496,0.001,0.00016276)
(0.333496,0.0001,0.00016276)
(0.333496,1e-05,0.00016276)
(0.333496,1e-06,0.00016276)
(0.333496,1e-07,0.00016276)
(0.333496,1e-08,0.00016276)
(0.333496,1e-09,0.00016276)
(0.333496,1e-10,0.00016276)
(0.333496,1e-11,0.00016276)
Replacing with fabs I get this:
(0.333496,0.001,0.00016276)
(0.333374,0.0001,4.06901e-05)
(0.333336,1e-05,2.54313e-06)
(0.333334,1e-06,6.35783e-07)
(0.333333,1e-07,3.97364e-08)
(0.333333,1e-08,9.93411e-09)
(0.333333,1e-09,6.20882e-10)
(0.333333,1e-10,3.88051e-11)
(0.333333,1e-11,9.7013e-12)