泰勒系列误差最多为10 ^ -3

时间:2015-12-10 02:54:46

标签: c taylor-series function-approximation

我试图计算最多cos(x)错误的10^-3和所有x ∈ [-pi/4, pi/4]的泰勒系列,这意味着我的错误必须小于{{ 1}}。我可以修改for循环中的x + =以获得不同的结果。我尝试了几个数字,但它永远不会变成小于0.001的错误。

0.001

我也是为#include <stdio.h> #include <math.h> float cosine(float x, int j) { float val = 1; for (int k = j - 1; k >= 0; --k) val = 1 - x*x/(2*k+2)/(2*k+1)*val; return val; } int main( void ) { for( double x = 0; x <= PI/4; x += 0.9999 ) { if(cosine(x, 2) <= 0.001) { printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2)); } printf("cos(x) : %10g %10g %10g\n", x, cos(x), cosine(x, 2)); } return 0; } 做这件事。对于这部分,e^x

x must in [-2,2]

但每当我更改for循环中的术语数时,它总是会有一个大于1的错误。我想如何将其更改为错误小于float exponential(int n, float x) { float sum = 1.0f; // initialize sum of series for (int i = n - 1; i > 0; --i ) sum = 1 + x * sum / i; return sum; } int main( void ) { // change the number of x in for loop so you can have different range for( float x = -2.0f; x <= 2.0f; x += 1.587 ) { // change the frist parameter to have different n value if(exponential(5, x) <= 0.001) { printf("e^x = %f\n", exponential(5, x)); } printf("e^x = %f\n", exponential(5, x)); } return 0; }

谢谢!

2 个答案:

答案 0 :(得分:0)

我的理解是,为了提高精确度,你需要在泰勒系列中考虑更多的术语。例如,考虑一下发生了什么 你试图通过泰勒系列计算e(1)。

$ e(x)= \ sum \ limits_ {n = 0} ^ {\ infty} frac {x ^ n} {n!} $

我们可以考虑扩展e(1)中的前几个术语:

n             value of nth term           sum
0        x^0/0! = 1                   1
1        x^1/1! = 1                   2
2        x^2/2! = 0.5                 2.5
3        x^3/3! = 0.16667             2.66667
4        x^4/4! = 0.04167             2.70834

你应该注意两件事,首先,随着我们添加更多术语,我们越来越接近e(1)的确切值,同时连续总和之间的差异越来越小。

因此,e(x)的实现可以写成:

#include <stdbool.h>
#include <stdio.h>
#include <math.h>

typedef float (*term)(int, int);
float evalSum(int, int, int, term);
float expTerm(int, int);
int fact(int);
int mypow(int, int);
bool sgn(float);

const int maxTerm = 10;         // number of terms to evaluate in series
const float epsilon = 0.001;    // the accepted error

int main(void)
{
    // change these values to modify the range and increment 
    float   start = -2;
    float   end = 2;
    float   inc = 1;

    for(int x = start; x <= end; x += inc)
    {
        float value = 0;
        float prev = 0;

        for(int ndx = 0; ndx < maxTerm; ndx++)
        {
            value = evalSum(0, ndx, x, expTerm);

            float diff = fabs(value-prev);
            if((sgn(value) && sgn(prev)) && (diff < epsilon))
                 break;
            else
                 prev = value;
        }

        printf("the approximate value of exp(%d) is %f\n", x, value);
    }

    return 0;
}

我猜测我们不需要在扩展中使用超过10个术语来获得所需的精度,因此内部for循环是我们在n中循环的值。范围[0,10]。

另外,我们有几行致力于检查我们是否达到了所需的精度。首先,我计算当前评估与先前评估之间差异的绝对值,并取绝对差值。检查差异是否小于我们的epsilon值(1E-3)是提前退出循环的标准。我还需要检查当前值和先前值的符号是否相同,因为计算e(-1)的值有一些波动,这就是条件中的第一个子句正在做的事情。

float evalSum(int start, int end, int val, term fnct)
{
    float sum = 0;
    for(int n = start; n <= end; n++)
    {
        sum += fnct(n, val);
    }

   return sum;
}

这是我编写的一个实用函数,用于评估系列的第一个n项。 start是起始值(此代码始终为0),end是结束值。最后一个参数是一个指向函数的指针,该函数表示如何计算给定的术语。在此代码中,fnct可以是指向任何取整数参数并返回浮点数的函数的指针。

float expTerm(int n, int x)
{
    return (float)mypow(x,n)/(float)fact(n);
}

在这个单行功能中被埋没是大多数工作发生的地方。该函数表示e(n)的泰勒展开的闭合形式。仔细观察上面的内容,您应该能够看到我们正在为给定的x和n值计算$ \ fract {x ^ n} {n!} $。作为提示,对于余弦部分,您需要创建一个函数来评估cos的泰勒展开中的一个项的闭合。这是由$( - 1)^ n \ fact {x ^ {2n}} {(2n)!} $给出的。

int fact(int n)
{
    if(0 == n)
        return 1;             // by defination
    else if(1 == n)
        return 1;
    else
        return n*fact(n-1);
}

这只是阶乘函数的标准实现。这里没什么特别的。

int mypow(int base, int exp)
{
    int result = 1;

    while(exp)
    {
        if(exp&1)              // b&1 quick check for odd power
        {
            result *= base;
        }

        exp >>=1;              // exp >>= 1 quick division by 2
        base *= base;
    }

    return result;
}

用于取幂的自定义函数。我们当然可以使用<math.h>中的版本,但因为我知道我们只会做整数幂,所以我们可以编写一个优化版本。提示:在执行余弦处理时,您可能需要使用<math.h>中的版本来处理浮点数。

bool sgn(float x)
{
    if(x < 0) return false;
    else return true;
}

确定浮点值符号的极其简单的函数,返回true为正,否则为false。

此代码是使用gcc版本4.8.4在我的Ubuntu-14.04上编译的:

******@crossbow:~/personal/projects$ gcc -std=c99 -pedantic -Wall series.c -o series
******@crossbow:~/personal/projects$ ./series
the approximate value of exp(-2) is 0.135097
the approximate value of exp(-1) is 0.367857
the approximate value of exp(0) is 1.000000
the approximate value of exp(1) is 2.718254
the approximate value of exp(2) is 7.388713

使用 bc 给出的预期值为:

******@crossbow:~$ bc -l
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
e(-2)
.13533528323661269189
e(-1)
.36787944117144232159
e(0)
1.00000000000000000000
e(1)
2.71828182845904523536
e(2)
7.38905609893065022723

如您所见,这些值完全在您请求的容差范围内。我把它作为练习来做余弦部分。

希望这有帮助,
-T

答案 1 :(得分:0)

expcos具有在实线上无处不在的幂级数。对于任何有界区间,例如[-pi/4, pi/4][-2, 2],幂级数不仅仅是逐点收敛,而是统一收敛到expcos

逐点收敛意味着对于区域中的任何x以及任何epsilon > 0,您可以选择足够大的N,以便从第一个{{1}获得近似值泰勒系列的术语在真值的N范围内。但是,对于逐点收敛,epsilon对于某些N可能较小而对其他x较大,并且由于存在无限多x个,因此可能没有有限N适应所有人的。对于某些功能而言,有时会发生这种情况。

均匀收敛意味着对于任何epsilon > 0,您可以选择足够大的N,以使该区域中的每个epsilon的近似值都在x范围内。这就是你正在寻找的那种近似,你保证这就是你所拥有的那种融合。

原则上,您可以查看expcos在任何有限域上均匀收敛的证明之一,坐下来说“如果我们采取epsilon = .001会怎样,并且区域是......“,并使用笔和纸计算N上的一些有限界限。然而,大多数这些证明将在某些步骤中使用一些不明确的估计值,因此您计算的N的值将大于必要值 - 可能要大得多。将N作为变量实现它会更简单,然后像在代码中一样使用for循环检查值,看看你需要多大才能使误差小于.001无处不在。

所以,我不知道你需要选择的N的正确值是什么,但数学保证如果你不断尝试更大的值,你会找到一个有用的值。