对于我的学习,我必须使用此函数对算法进行编码以计算sin()
:
但是,在我的算法中,我必须将X的值保持在0和Pi / 2之间。所以,我编写了算法但所有结果都是错误的。
这是我的代码:
double sinX(double x){
double resultat = 0;
int i;
if(x < 0 || 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
答案 0 :(得分:7)
你误解了你展示的第二个公式的目的。我们的想法是,您使用该公式计算前一词中总和中的每个词,从而使您无需使用任何pow
或factorial
个来电。
#include <stdio.h>
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
这应该会为0
到pi / 2
的范围提供合理的结果。在该范围之外,您需要对使用的减少更加谨慎:简单地减少模pi / 2
将无法给出正确的结果。 (提示:减少模2 * pi
是安全的,因为sin
函数是周期性的2 * pi
。现在使用sin
函数的对称性来缩减到0
范围1}}到pi / 2
。)
编辑解释为什么当前代码提供的结果不正确:除了有缺陷的缩减步骤之外,在您的总和中,您从术语i = 1
开始。但第一个术语应该是i = 0
(这是x
术语,而i=1
术语是-x^3 / 3!
术语。快速而又脏的修复方法是删除还原步骤,并将resultat
变量初始化为x
而不是0
。这应该可以为小x
提供良好的结果,然后您可以找出如何替换减少步骤。如果您真的打算使用显式因子和幂函数来计算答案,我会感到惊讶,但我几乎可以肯定,如上所述,您可以预期从前一个项计算每个项。
答案 1 :(得分:3)
您的代码存在两个问题:
sin(x+k*π/2)
不一定等于sin(x)
i=0
的值开始,然后使用问题中的等式计算每次迭代中的下一个术语。答案 2 :(得分: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;
}
答案 3 :(得分:0)
关于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;
}