Search code examples
coptimizationbisection

Bisection method. Optimise function in C code


I have a comment from my teacher related to my code for bisection method. He said "The number of calculations of the function is not optimised. In fact, on each iteration, the function is calculated three times, although it would be enough once."

Could you please help me to optimise the calculations. I actually don't even see at which point the function is calculated 3 times.

#include<stdio.h>
#include<math.h>
#include<time.h>

double f(double x); //Function
int res(int i, double a, double b, double ξ, double ε1, double ε2); //Print result
double Bisection(double a, double b, double ε1, double ε2); //Bisection method

int main()
{
    double a=-10, b=0, ξ, h=0.5, α, x1, x2, ε1, ε2;
    int i=0;

    printf("\nf(x) = 2^x - 2 * cos(x)");
    printf("\nStart of the interval a = %.0lf", a);
    printf("\nEnd of the interval b = %.0lf", b);
    printf("\nEnter error ε1 for function = ");
    scanf("%lf", &ε1);
    printf("Enter error ε2 for argument = ");
    scanf("%lf", &ε2);
    printf("\n\nSOLUTION:");

    //selection of roots
    x1=a;
    x2=x1+h;
    while (x2<=b)
    {
        if ((f(x1)*f(x2))<0) 
        {
            i++;
            printf("\n\n%d) %d root of the function is in the interval [%.1f, %.1f]\n",i, i, x1, x2);
            printf("\nn\t     a\t\t   b\t\t ξ\t     f(ξ)\t     ε1\t\t    ε2\n");
            Bisection(x1,x2,ε1,ε2); //Bisection method
        }
        x1=x2;
        x2=x1+h;
    }
    return 0;
}

//Function
double f(double x) 
{
   double y;
   y=pow(2,x)-2*cos(x);
   return y;
}

//Print result
int res(int i, double a, double b, double ξ, double ε1, double ε2) 
{
   printf("%d\t%10.7f    %10.7f    %10.7f    %10.7f    %e    %e\n", i, a, b, ξ, f(ξ), ε1, ε2);
   return 0;
}

//Bisection method
double Bisection(double a, double b, double ε1, double ε2)
{
    double ξ=(a+b)/2; //Middle of the interval
    double α;
    int i=0;
    if (f(ξ)==0) 
    {
        printf("Root: %f \n\n", ξ);
    }
    else 
    {
        while ((fabs(f(ξ))>ε1) && ((fabs(b-a)/2)>ε2)) //The accuracy of the definition of the root
        {
            if ((f(a)*f(ξ))<0) 
            {
                b=ξ;
            }
            else 
            {
                a=ξ;
            }
            ξ=(a+b)/2;
            res(i+1, a, b, ξ, ε1, ε2); //Print results
            i++;
        }
        printf("Root ξ=%.7f found after %d iterations\n", ξ, i);
        printf("Function f(ξ)=%.10f found after %d iterations\n", f(ξ), i);
    }
    return 0;
}

Results


Solution

  • Only including relevant lines

    Replace:

    double Bisection(double a, double b, double ε1, double ε2)
    {
        double ξ=(a+b)/2;
    
        if (f(ξ)==0) 
    
        else 
        {
            while ((fabs(f(ξ))>ε1) && ((fabs(b-a)/2)>ε2))
            {
                if ((f(a)*f(ξ))<0) 
    
                ξ=(a+b)/2;
            }
       }
    

    with

    double Bisection(double a, double b, double ε1, double ε2)
    {
        double ξ=(a+b)/2; 
    
        double val = f(ξ); // Here is the magic
    
        if (val==0) 
    
        else 
        {
            while ((fabs(val)>ε1) && ((fabs(b-a)/2)>ε2))
            {
                if ((f(a) * val )<0) 
    
                ξ=(a+b)/2;
                val = f(ξ); // And here
           }
       }
    

    It's not really some secret trick we're talking about. It's only about saving the return value in a variable and use that variable instead of a function call whenever possible. If the argument to the function changes, then you need to execute the function again. Here is a simple example that makes a string uppercase.

    void uppercase(char *str) {
        // Bad, because it's not necessary to calculate the string
        // length every iteration.
        for(size_t i=0; i<strlen(str); i++)     
            str[i] = toupper(str[i]);
    }
    
    // Instead, do this
    
    void uppercase(char *str) {
        size_t len = strlen(str);    // Precalculate and reuse in loop
        for(size_t i=0; i<len; i++)            
            str[i] = toupper(str[i]);
    }