问题描述
我的老师对我的二分法代码发表了评论。他说“函数的计算次数没有优化。实际上,在每次迭代中,函数都会计算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;
}
解决方法
只包含相关行
替换:
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]);
}