我最近写了一篇计算机科学考试,他们要求我们给cos泰勒系列扩展一个递归定义。这是系列
cos(x)= 1 - x ^ 2/2! + x ^ 4/4! + x ^ 6/6! ...
,函数签名如下
float cos(int n , float x)
其中n表示用户想要计算的系列中的数字,x表示cos函数中x的值
我显然没有把这个问题弄错,过去几天我一直试图解决这个问题,但是我碰到了一堵砖墙
有人能帮助我开始某个地方吗?
答案 0 :(得分:2)
到目前为止,所有答案每次都会重新计算因子。我当然不会这样做。相反,你可以写:
float cos(int n, float x)
{
if( n > MAX )
return 1;
return 1-x*x/( (2*n-1)*2*n ) * cos(n+1, x);
}
考虑到cos返回以下内容(抱歉点位置):
你可以看到n> MAX,n = MAX,等等。标志的交替和x的力量很容易看到。
最后,在n = 1时你得到0! = 1,因此调用cos(1, x)
可以得到cos的泰勒展开的第一个MAX项。
通过开发(当条款很少时更容易看到),您可以看到第一个公式等同于以下内容:
对于n> 0,你在cos(n-1,x)中除以前一个结果的(2n-3)(2n-2),乘以x²。您可以看到,当n = MAX + 1时,此公式为1,n = MAX,则为1-x²/((2MAX-1)2MAX)
,依此类推。
如果您允许自己的帮助函数,那么您应该将上面的签名更改为float cos_helper(int n, float x, int MAX)
并将其调用为:
float cos(int n, float x) { return cos_helper(1, x, n); }
编辑:将n
的含义从评估期限的程度(如此答案到目前为止)转换为术语数(如问题及以下所示),但仍未重新计算总因数每次,我建议使用两个关系。
让我们简单地定义cos(0,x) = 0
和cos(1,x) = 1
,并试图通常得到cos(n,x)泰勒级数的n个第一项的总和。
然后对于每个n> 0,我们可以写cos,cos(n,x)来自cos(n-1,x):
cos(n,x)= cos(n-1,x)+ x 2n /(2n)!
现在为n> 1,我们尝试使cos(n-1,x)的最后一个项出现(因为它是我们想要添加的最接近的术语):
cos(n,x)= cos(n-1,x)+x²/((2n-1)2n)*(x 2n-2 /(2n-2)!)
将此公式与前一个公式相结合(将其调整为n-1而不是n):
cos(n,x)= cos(n-1,x)+x²/((2n-1)2n)*(cos(n-1,x) - cos(n-2,x))< / p>
我们现在有一个纯粹递归的cos(n,x)定义,没有辅助函数,没有重新计算阶乘,并且n是泰勒分解总和中的项数。
但是,我必须强调以下代码的表现非常糟糕:
cos(n-1,x)
cos( (n-1) - 1, x)
现在这个免责声明已经到位,代码如下:
float cos(int n, float x)
{
if( n < 2 )
return n;
float c = x * x / ( 2 * (n-1) * 2 * n );
return (1-c) * cos(n-1, x) + c * cos(n-2, x);
}
答案 1 :(得分:1)
cos(x)=1 - x^2/2! + x^4/4! - x^6/6! + x^8/8!.....
=1-x^2/2 (1 - x^2/3*4 + x^4/3*4*5*6 -x^6/3*4*5*6*7*8)
=1 - x^2/2 {1- x^2/3*4 (1- x^2/5*6 + x^4/5*6*7*8)}
=1 - x^2/2 [1- x^2/3*4 {1- x^2/5*6 ( 1- x^2/7*8)}]
double cos_series_recursion(double x, int n, double r=1){
if(n>0){
r=1-((x*x*r)/(n*(n-1)));
return cos_series_recursion(x,n-2,r);
}else return r;
}
答案 2 :(得分:0)
就像总和一样。
n
中的参数float cos(int n , float x)
是l
,现在就这样做......
一些伪代码:
float cos(int n , float x)
{
//the sum-part
float sum = pow(-1, n) * (pow(x, 2*n))/faculty(2*n);
if(n <= /*Some predefined maximum*/)
return sum + cos(n + 1, x);
return sum;
}
答案 3 :(得分:0)
你可以使用循环或递归,但我会建议一个循环。无论如何,如果你必须使用递归,你可以使用类似下面的代码
#include <iostream>
using namespace std;
int fact(int n) {
if (n <= 1) return 1;
else return n*fact(n-1);
}
float Cos(int n, float x) {
if (n == 0) return 1;
return Cos(n-1, x) + (n%2 ? -1 : 1) * pow (x, 2*n) / (fact(2*n));
}
int main()
{
cout << Cos(6, 3.14/6);
}
答案 4 :(得分:0)
当您想要递归但函数参数不包含您需要的信息时,通常的技巧是引入 帮助函数 来执行递归。
我的印象是,在Lisp世界中,惯例是命名这样一个函数something-
aux
( auxiliary 的缩写),但在过去,这可能只是一个有限的群体。
无论如何,这里的主要问题是n
表示递归的自然终点,即基本情况,然后您还需要一些自身工作到n
的索引。所以,这是辅助功能额外参数的一个很好的候选者。另一位候选人来自于考虑该系列的一个术语与前一个术语的关系。
答案 5 :(得分:0)
一种使用静态变量的简单方法:
double cos(double x, int n) {
static double p = 1, f = 1;
double r;
if(n == 0)
return 1;
r = cos(x, n-1);
p = (p*x)*x;
f = f*(2*n-1)*2*n;
if(n%2==0) {
return r+p/f;
} else {
return r-p/f;
}
}
请注意,我在操作中将2*n
乘以得到下一个阶乘。
使n
与我们所需的阶乘保持一致,使此操作很容易在2个操作中完成:先由f = f * (n - 1)
然后f = f * n
。
when n = 1, we need 2!
when n = 2, we need 4!
when n = 3, we need 6!
因此,我们可以安全地将n
加倍,然后从那里开始工作。我们可以这样写:
n = 2*n;
f = f*(n-1);
f = f*n;
如果执行此操作,则由于将if((n/2)%2==0)
的值加倍,因此需要将偶/奇校验更新为n
。
这可以改写为f = f*(2*n-1)*2*n;
,现在我们不必检查n
是偶数还是奇数,因为n
未被更改。