计算函数sin()

对于我的学习,我必须使用此函数编写一个算法来计算sin()

但是,在我的算法中,我必须将X的值保持在0和Pi / 2之间。 所以,我编写了算法但所有结果都是错误的。

这是我的代码:

 double sinX(double x){ double resultat = 0; int i; if(x  M_PI_2) x = fmod(x,M_PI_2); for(i = 1;i<=30;i++){ resultat += -1 * ((x*x)/(2*i*(2*i+1)))*(pow(-1,i-1))*((pow(x,2*i-1))/(factorielle(2*i-1))); } return resultat; } 

我找不到原因。 你能帮助我吗?

这里是X的几个值和fmod的结果

 1 / 1 2 / 0.429204 3 / 1.4292 4 / 0.858407 5 / 0.287611 6 / 1.28761 7 / 0.716815 8 / 0.146018 9 / 1.14602 10 / 0.575222 11 / 0.00442571 12 / 1.00443 13 / 0.433629 14 / 1.43363 15 / 0.862833 16 / 0.292037 17 / 1.29204 18 / 0.72124 19 / 0.150444 20 / 1.15044 

以及算法的结果

 1 / -0.158529 2 / -0.0130568 3 / -0.439211 4 / -0.101605 5 / -0.00394883 6 / -0.327441 7 / -0.0598281 8 / -0.000518332 9 / -0.234888 10 / -0.0312009 11 / -1.44477e-008 12 / -0.160572 13 / -0.0134623 14 / -0.443022 15 / -0.103145 16 / -0.00413342 17 / -0.330639 18 / -0.0609237 19 / -0.000566869 20 / -0.237499 

这是我的“factorielle”定义

 double factorielle(double x){ double resultat = 1; int i; if(x != 0){ for (i=2;i<=x;i++) { resultat *= i; } } else{ resultat = 1; } return resultat; } 

和价值观:

 1 / 1 2 / 2 3 / 6 4 / 24 5 / 120 6 / 720 7 / 5040 8 / 40320 9 / 362880 10 / 3.6288e+006 11 / 3.99168e+007 12 / 4.79002e+008 13 / 6.22702e+009 14 / 8.71783e+010 15 / 1.30767e+012 16 / 2.09228e+013 17 / 3.55687e+014 18 / 6.40237e+015 19 / 1.21645e+017 20 / 2.4329e+018 

你误解了你展示的第二个公式的目的。 我们的想法是,您使用该公式计算前一项中总和的每个 ,从而使您无需使用任何powfactorial调用。

 #include  double sinX(double x) { double term, total_so_far; int i; term = x; /* First term in the expansion. */ total_so_far = 0.0; for (i = 1; i <= 30; i++) { /* Add current term to sum. */ total_so_far += term; /* Compute next term from the current one. */ term *= -(x * x) / (2*i) / (2*i + 1); } return total_so_far; } int main(void) { /* testing */ double x; int i; for (i = 0; i <= 10; i++) { x = i / 10.0; printf("sin(%f) is %f\n", x, sinX(x)); } return 0; } 

以及在我的机器上运行此代码的结果:

 sin(0.000000) is 0.000000 sin(0.100000) is 0.099833 sin(0.200000) is 0.198669 sin(0.300000) is 0.295520 sin(0.400000) is 0.389418 sin(0.500000) is 0.479426 sin(0.600000) is 0.564642 sin(0.700000) is 0.644218 sin(0.800000) is 0.717356 sin(0.900000) is 0.783327 sin(1.000000) is 0.841471 

这应该给你0pi / 2范围的合理结果。 在该范围之外,你需要对你正在使用的减少更加谨慎:简单地减少模数pi / 2将不会给出正确的结果。 (提示:减少模2 * pi是安全的,因为sin函数是周期性的,周期为2 * pi 。现在使用sin函数的对称性减小到0pi / 2的范围。)


编辑解释为什么当前代码给出不正确的结果:除了有缺陷的减少步骤之外,在你的总和中,你从术语i = 1 。 但第一项应该是i = 0 (这是x项,而i=1项是-x^3 / 3!项)。 快速而又脏的修复方法是删除还原步骤,并将resultat变量初始化为x而不是0 。 这应该可以为小x提供良好的结果,然后您可以找出如何替换减少步骤。 如果您真的打算使用显式因子和功率调用来计算答案,我会感到惊讶 - 我几乎可以肯定,如上所述,您可以预期从前一个项计算每个项。

您的代码有两个问题:

  1. sin(x+k*π/2)不一定等于sin(x)
  2. 你对这个词的表达有点搞砸了。 说明似乎建议您计算上一学期系列中的下一学期。 从i=0的值开始,然后使用问题中的等式计算每次迭代中的下一个项。

最后,我跟着你的指示。 这是我的最终代码:

 double sinX(double x) { double result = 1.0; double term_i = 1.0; int i = 2; x = fmod(x, 2*M_PI); for(i = 2; i<= 30; i+=2) { term_i = (-term_i * (x*x)) / (i*(i+1)); result += term_i; } return x * result; } 

关于OP发布的答案的术语数量的想法。

只要首先执行一些范围限制,如fmod() ,所需的术语数量可以动态地合理确定。 (对于x:0到2 * pi,使用1到23次迭代。)

 double sinX1(double x) { double result = 1.0; double term_i = 1.0; int i = 2; x = fmod(x, 2*M_PI); // for(i = 2; i<= 30; i+=2) for(i = 2; ((1.0 + term_i) != 1.0); i+=2) { term_i = (-term_i * (x*x)) / (i*(i+1)); result += term_i; } return x * result; }