二分法在 C 代码中优化函数

问题描述

我的老师对我的二分法代码发表了评论。他说“函数的计算次数没有优化。实际上,在每次迭代中,函数都会计算3次,尽管一次就足够了。”

你能帮我优化一下计算吗?实际上我什至没有看到函数在哪一点被计算了 3 次。

#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 ε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,x2);
            printf("\nn\t     a\t\t   b\t\t ξ\t     f(ξ)\t     ε1\t\t    ε2\n");
            bisection(x1,ε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 ε2) 
{
   printf("%d\t%10.7f    %10.7f    %10.7f    %10.7f    %e    %e\n",a,b,f(ξ),ε2);
   return 0;
}

//bisection method
double bisection(double a,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,ε2); //Print results
            i++;
        }
        printf("Root ξ=%.7f found after %d iterations\n",i);
        printf("Function f(ξ)=%.10f found after %d iterations\n",i);
    }
    return 0;
}

Results

解决方法

只包含相关行

替换:

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;
        }
   }

double Bisection(double a,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
       }
   }

我们谈论的并不是什么秘密技巧。它只是将返回值保存在一个变量中,并尽可能使用该变量而不是函数调用。如果函数的参数发生变化,则需要再次执行该函数。这是一个使字符串大写的简单示例。

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]);
}