我做了一个计算泰勒级数的程序,但是教授想让我们先除以再乘以来改变它。这是我的代码,我在第一部分中使用了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的结果(注意:我没有测试这个,这是理论)。编译器也完全有可能看到优化的机会并为您利用它。