手动实现反三角函数这些其实很多情况下是没有意义的,因为这些都是封装好的!可是就在发表这篇文章的前几天,就有人让我帮他实现,很多搞硬件的都会遇到这种情况………这个其实很容易,我用迈克劳林公式实现之后,突然又有点不明白,比如我们要求acos(0.6)的值,按照泰勒公式应该是求acos在0.6的n阶导数,怎么能只用acos在0处的n阶导数直接求得?直到几天后的今天我才想明白。
泰勒公式是这样的:
其中是
的高阶无穷小。其中迈克劳林公式是a为0时的特殊情况。如果仅仅是从这里来理解的话,确实,只有x趋向于a的时候,泰勒公式才能达到任意的精度。否则无穷小就无从谈起了。
但是,其实只是一种定性的描述,他被称为佩亚诺余项,我们充其量只能得出:当x趋向于a时,余项可以无穷小。但是却无法知道,当x不趋向与a时,余项是不是依然能足够小,这个条件是不充分的,为此,我们还需要定量的描述余项,来研究它的性质。
不过至少在发这篇文章的时候,百度百科和维基百科上的泰勒中值定理的介绍全是错的,实际上那是拉格朗日余项。真正的泰勒中值定理是更普适性的,像拉格朗日余项,柯西余项……都是它的特殊情况!
下面我们用拉格朗日余项来研究:
其实当时(这里ξ是x0与x之间的某个值),此余项就是拉格朗日余项,他之所以重要,是因为这里的x不需要趋向x0,因为它可以由柯西中值定理证得,而柯西中值定理实际上对区间两个端点距离是不做任何要求的!
于是我们可以看到只要n足够大,拉格朗日余项会趋向无穷小①,所以当我们只在0处展开泰勒公式求一个函数的近似值时,只要展开项数足够多,依然可以达到任意精度!
实际上我们看到,泰勒公式的精度可以用两种方式达到:x与x0的间距足够小或者是展开项数足够多。
以上是理论证明,但是它的实现却很简单,可以查一下反三角函数acos的泰勒展开:
arccos x = π/2 - ( x + 1/2*x^3/3 + 1*3/(2*4)*x^5/5 + …… ) (|x|<1)
然后用C实现:
<span style="font-family:KaiTi_GB2312;font-size:18px;">float aacos(float x){
unsigned char i;
float ans=x,t1=1,t2=x;x*=x;
for(i=3;i<51;i+=2){
t1*=(float)(i-2)/(float)(i-1);
t2*=x;
ans+=(t1*t2/(float)i);
}
return ans=1.5708-ans;
}</span>
可以用C的封装好的acos()函数测试一下:
<span style="color:#330033;"><span style="font-family:KaiTi_GB2312;font-size:18px;">#include <stdio.h>
#include <math.h>
float aacos(float x){
unsigned char i;
float ans=x,t1=1,t2=x;x*=x;
for(i=3;i<51;i+=2){
t1*=(float)(i-2)/(float)(i-1);
t2*=x;
ans+=(t1*t2/(float)i);
}
return ans=1.5708-ans;
}
int main(){
float ang;
while(scanf("%f",&ang)!=EOF)
printf("%.5f %.5f\n",aacos(ang),acos(ang));
return 0;
}
</span></span>
可以发现任意输入一个数,几乎结果时一模一样的,而这里我们只展开了前50项。
之所以用float型以及为何如此紧凑,是因为当一个人真正面对不得不手打一些数学函数的时候,一般是不会有double型的,而且能用char就尽量用char!
同样,我们还可以实现sqrt()函数,log()函数以及一些其他的数学函数。
ps:
其实①的论证还不严谨,它也只是看起来像无穷小而已,要想真正达到无穷小,必须说明分子是有上界的,而我还不能说明,不过当我发现的时候,我会重新修改!