误差至多为 10^-3 的泰勒级数
taylor series with error at most 10^-3
我正在尝试计算 cos(x)
的泰勒级数,错误最多 10^-3
并且对于所有 x ∈ [-pi/4, pi/4]
,这意味着我的错误需要小于 0.001
。我可以修改 for 循环中的 x += 以获得不同的结果。我尝试了几个数字,但它永远不会变成小于 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]
。
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;
}
但是每当我改变 for 循环中的项数时,它总是有一个大于 1 的错误。我应该如何将它更改为小于 10^-3
的错误?
谢谢!
我的理解是,要提高精度,您需要考虑泰勒级数中的更多项。例如,考虑当
您尝试通过泰勒级数计算 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;
}
我猜测我们不需要在扩展中使用十个以上的项来达到所需的精度,因此内部 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 可以是指向任何采用整数参数和 returns 浮点数的函数的指针。
float expTerm(int n, int x)
{
return (float)mypow(x,n)/(float)fact(n);
}
隐藏在这个单行函数中的是大部分工作发生的地方。此函数表示 e(n) 的泰勒展开式的封闭形式。仔细看上面的内容,您应该能够看到我们正在计算 $\fract{x^n}{n!}$ 对于给定的 x 和 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。
此代码是在我的 Ubuntu-14.04 上使用 gcc 版本 4.8.4 编译的:
******@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
exp
和 cos
的幂级数处处收敛于实线上。对于任何有界区间,例如[-pi/4, pi/4]
或 [-2, 2]
,幂级数不仅逐点收敛,而且一致收敛到 exp
和 cos
.
逐点收敛意味着对于区域中的任何 x
和任何 epsilon > 0
,您可以选择足够大的 N
以便从第一个 [=泰勒级数的 18=] 项在真值的 epsilon
以内。然而,随着逐点收敛,N
对于某些 x
可能很小,而对于其他 x
可能会很大,并且由于有无限多个 x
,因此可能没有有限的 N
可以容纳所有这些。对于某些功能,有时确实会发生这种情况。
均匀收敛意味着对于任何 epsilon > 0
,您可以选择足够大的 N
,以便该区域中的每个 x
的近似值都在 epsilon
之内。这就是您正在寻找的那种近似值,并且可以保证这就是您所拥有的那种收敛性。
原则上你可以看一下 exp
、cos
在任何有限域上一致收敛的证明之一,坐下来说 "what if we take epsilon = .001
, and the regions to be ...",然后计算一些有限界N
使用笔和纸。然而,这些证明中的大多数将在某些步骤中使用一些不准确的估计,因此您计算的 N
的值将比必要的大——可能大得多。将 N
作为变量来实现它会更简单,然后像您在代码中所做的那样使用 for 循环检查值,并查看必须将其设置为多大才能使错误小于.001
无处不在。
所以,我无法判断您需要选择的 N
的正确值是什么,但数学保证如果您继续尝试更大的值,最终您会找到一个有效的值。
我正在尝试计算 cos(x)
的泰勒级数,错误最多 10^-3
并且对于所有 x ∈ [-pi/4, pi/4]
,这意味着我的错误需要小于 0.001
。我可以修改 for 循环中的 x += 以获得不同的结果。我尝试了几个数字,但它永远不会变成小于 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]
。
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;
}
但是每当我改变 for 循环中的项数时,它总是有一个大于 1 的错误。我应该如何将它更改为小于 10^-3
的错误?
谢谢!
我的理解是,要提高精度,您需要考虑泰勒级数中的更多项。例如,考虑当 您尝试通过泰勒级数计算 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;
}
我猜测我们不需要在扩展中使用十个以上的项来达到所需的精度,因此内部 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 可以是指向任何采用整数参数和 returns 浮点数的函数的指针。
float expTerm(int n, int x)
{
return (float)mypow(x,n)/(float)fact(n);
}
隐藏在这个单行函数中的是大部分工作发生的地方。此函数表示 e(n) 的泰勒展开式的封闭形式。仔细看上面的内容,您应该能够看到我们正在计算 $\fract{x^n}{n!}$ 对于给定的 x 和 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。
此代码是在我的 Ubuntu-14.04 上使用 gcc 版本 4.8.4 编译的:
******@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
exp
和 cos
的幂级数处处收敛于实线上。对于任何有界区间,例如[-pi/4, pi/4]
或 [-2, 2]
,幂级数不仅逐点收敛,而且一致收敛到 exp
和 cos
.
逐点收敛意味着对于区域中的任何 x
和任何 epsilon > 0
,您可以选择足够大的 N
以便从第一个 [=泰勒级数的 18=] 项在真值的 epsilon
以内。然而,随着逐点收敛,N
对于某些 x
可能很小,而对于其他 x
可能会很大,并且由于有无限多个 x
,因此可能没有有限的 N
可以容纳所有这些。对于某些功能,有时确实会发生这种情况。
均匀收敛意味着对于任何 epsilon > 0
,您可以选择足够大的 N
,以便该区域中的每个 x
的近似值都在 epsilon
之内。这就是您正在寻找的那种近似值,并且可以保证这就是您所拥有的那种收敛性。
原则上你可以看一下 exp
、cos
在任何有限域上一致收敛的证明之一,坐下来说 "what if we take epsilon = .001
, and the regions to be ...",然后计算一些有限界N
使用笔和纸。然而,这些证明中的大多数将在某些步骤中使用一些不准确的估计,因此您计算的 N
的值将比必要的大——可能大得多。将 N
作为变量来实现它会更简单,然后像您在代码中所做的那样使用 for 循环检查值,并查看必须将其设置为多大才能使错误小于.001
无处不在。
所以,我无法判断您需要选择的 N
的正确值是什么,但数学保证如果您继续尝试更大的值,最终您会找到一个有效的值。