cos泰勒级数展开式c ++的递归算法

时间:2014-12-01 17:54:09

标签: c++ math recursion cos

我最近写了一篇计算机科学考试,他们要求我们给cos泰勒系列扩展一个递归定义。这是系列

cos(x)= 1 - x ^ 2/2! + x ^ 4/4! + x ^ 6/6! ...

,函数签名如下

float cos(int n , float x)

其中n表示用户想要计算的系列中的数字,x表示cos函数中x的值

我显然没有把这个问题弄错,过去几天我一直试图解决这个问题,但是我碰到了一堵砖墙

有人能帮助我开始某个地方吗?

6 个答案:

答案 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返回以下内容(抱歉点位置):

cos function formula

你可以看到n> MAX,n = MAX,等等。标志的交替和x的力量很容易看到。

最后,在n = 1时你得到0! = 1,因此调用cos(1, x)可以得到cos的泰勒展开的第一个MAX项。

通过开发(当条款很少时更容易看到),您可以看到第一个公式等同于以下内容:

reformulation cos formula

对于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) = 0cos(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)
  • 精确的,因为取消效应:我们获得x 2n-2 /(2n-2)的精度!非常糟糕

现在这个免责声明已经到位,代码如下:

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)

就像总和一样。

cos

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未被更改。