我做了一个计算泰勒级数的程序,但是教授想让我们先除以再乘以来改变它。这是我的代码,我在第一部分中使用了divide()。我的power()和fact()只是对旧代码的引用。

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

int main()
{
double  x, mySin(), myCos(), myExp();
char    more;

do      {
    printf ("\n\t\t\t\t\tInput x: ");
    scanf  ("%lf", &x);
    printf ("\n\t\t\t\t\t\t\tLibraryResult  \t MyResult");
    printf ("\n\t\t\tSin(%6.2f)\t      %9.6f\t\t%9.6f", x, sin(x), mySin(x));
    printf ("\n\t\t\tCos(%6.2f)\t      %9.6f\t\t%9.6f", x, cos(x), myCos(x));
    printf ("\n\t\t\tExp(%6.2f)\t      %9.6f\t\t%9.6f", x, exp(x), myExp(x));
    printf ("\n\n\t\t\t\t\tDo more (Y/N) ?");
    scanf  ("%s", &more);
} while (more == 'y' || more == 'Y');
}

double mySin(double x)
{
double sum = 0., divide();
int    i, sign = 1;

for (i = 0; i < 30; i++, sign = - sign)
    sum = sum + sign * divide(x) ; //power(x, 2 * i + 1) / fact(2 * i + 1);

return sum;
}

double myCos(double x)
{
double sum = 0., divide();
int    i, sign = 1;

for (i = 0; i < 30; i++, sign = - sign)
    sum = sum + sign * divide(x);//power(x, 2 * i) / fact(2 * i);

return sum;

}

double myExp(double x)
{
double sum = 0., divide();
int i;

for (i= 0; i < 30; i++)
    sum = sum + divide(x); //power(x, i) / fact(i);


return sum;
}


double divide(int n, double x)
{
int i;
double div = 1.;

for (i = 1; i < n; i++)
    div =  x / i;

return div;

}

/*double fact(int n)
{
int i;
double prod = 1.;

for (i = 1; i <= n; i++)
    prod = prod * i;

return prod;
}

double power (double x, int n)
{
int i;
double prod = 1.;

for (i = 0; i < n; i++)
    prod = prod * x;

return prod;
}
*/

我一直在修改代码,在divide()中,输入x时使用I

最佳答案

我想我会给你一个答案,因为你的问题是系统性的。
首先,将函数拉到forward声明中。没有更多:

double  x, mySin(), myCos(), myExp();

把这个放在上面:
double divide(int n, double x);
double mySin(double x);
double myCos(double x);
double myExp(double x);

这也为您提供了一个很好的机会来记录它们的作用。这实际上会解决你的问题!(是的,即使文档只是一个注释):
// Returns x^n / n!
double divide(int n, double x);

看了那条评论,突然间int main()变得毫无意义:
sum = sum + sign * divide(x); // this is sum += sign * x^? / ?!

所以,纠正mySin看起来像这样:(注意,从循环语句中提取逻辑通常是一个好主意)
// The series for sin(x) starts with x^1/1 and continues by increasing by 2
for (i = 1; i < 30; i += 2) {
    sum += sign * divide(i,x); // += saves you from writing sum + ...
    sign = -sign;
}

这会产生正确的输出,但不会。不幸的是,您的mySin也有问题。记住它的文档,让我们看看它:
double divide(int n, double x)
{
int i;
double div = 1.;

for (i = 1; i < n; i++)
    div =  x / i;

return div;

}

这是非常接近正确的,只是等号不是很正确。每次迭代都要乘以x/i。
for (i = 1; i < n; i++)
    div *= x / i;

更接近,但让我们来计算循环的次数。它的n-1次(如果我们从0开始,它将是n次,但是我们会有一个除以0的错误)。我们来解决这个问题:
for (i = 1; i <= n; i++)
    div *= x / i;

从技术上讲,这是在乘法的同时进行除法,这将产生最精确的结果(通过保持div接近“正常”数)。如果你先除数,你将开始使用非常小的数字,如果你先乘法,你将开始使用非常大的数字。不管怎样,你都会失去准确性(因为double在中等大小的数字上是最准确的)。如果你真的把循环分开,它会变成:
分割循环:
for (i = 1; i <= n; i++)
    div /= i;

乘法循环:
for (i = 1; i <= n; i++)
    div *= x;

对于大多数输入来说,这根本不会有什么区别。然而,如果你有“极端”的价值观,你最终会杀死你的双打。例如,当首先相乘时,如果使用x=1000,则在实际开始除法之前,将用完double的空间。结果会是南,因为替身根本无法应付。类似地,如果你增加迭代次数(而不是30次,做30000000次),显然需要更长的时间(当然是100000次),但是如果你也先除以,在你开始乘法之前,你会把你的二重数归零。因此您将得到0的结果(注意:我没有测试这个,这是理论)。编译器也完全有可能看到优化的机会并为您利用它。

08-19 18:39