admin管理员组

文章数量:1794759

C/C++实现三角函数的方法

C/C++实现三角函数的方法

前几天在超算学堂上用C语言做一个并行计算求函数积分的作业,恰好平台不支持math.h头文件,于是自己设计了两种计算三角函数的方法,在这里进行总结。

首先最容易想到的是利用泰勒展开式:

注意泰勒展开式的分母部分,要知道int的最大值为2147483647 < 13!,所以当n=6时就要结束累和,而此时由于泰勒展开式的收敛速度并不快,所以误差仍然很大(当x=8时,利用泰勒展开式实现的sinx与math库中自带sinx的绝对误差已经超过了200),因此不能使用泰勒展开式来实现三角函数。

在这里介绍一种相对精确度好很多的实现三角函数的方法——利用CORDIC算法,关于CORDIC算法的介绍详见这篇博客:blog.csdn/liyuanbhu/article/details/8458769

在这里以求sin(x)为例,主要利用的是直角坐标旋转的公式:

x' = cos(θ)*x - sin(θ)*y y' = sin(θ)*x + cos(θ)*y

主要思路如下:给定一个弧度值a,函数从0开始,首先正向旋转π/4,直到旋转后的弧度值超过a,此时退回π/4,在继续正向旋转π/8,直到弧度值超过a,再退回π/8,再正向旋转π/16。。。如此循环直到旋转的弧度与a的误差小于一定值(下面代码中取π/16384),之后利用此时的x坐标和y坐标来计算出sin

算法的思路类似与二分查找,在实现算法时只需要知道特定几个弧度的三角函数值,就可以求出其它任意弧度的三角函数值,不存在溢出的问题,并且理论上精确度可以达到浮点数绝对值的最小值(精确度靠最终旋转弧度与a的误差和特定角度三角函数值的精确度决定)

由于最终我们要的只是坐标的比例,而不是精确的值,所以还可以上面的公式简化为(各项除以cos(θ)):

x' = x - tan(θ)*y y' = tan(θ)*x + y

这样只需要知道特定角度的tan值就可以了,代码如下:

double pi = 3.1415926535897932; double angle[] = {pi/4,pi/8,pi/16, pi/32,pi/64,pi/128, pi/256,pi/512,pi/1024, pi/2048,pi/4096,pi/8192,pi/16384}; double tang[]={1,0.4142135623731,0.19891236737966, 0.098491403357164,0.049126849769467, 0.024548622108925,0.012272462379566, 0.0061360001576234,0.0030679712014227, 0.0015339819910887,0.00076699054434309, 0.00038349521577144,0.00019174760083571}; double sinx(double a){ if(a <= (pi/16384)){ return a; //因为a的值太小,sin a 约等于 a }else{ //开始 CORDIC 算法 bool negitive = a < 0; // sin(-a) = -sin(a) double x = 10; double y = 0; double theta = 0; for(int i = 0;i < 13;i ++){ //开始迭代 double orix,oriy; while(theta < a){ //当前角度小于a orix = x; oriy = y; //坐标旋转 x = orix - tang[i] * oriy; y = tang[i] * orix + oriy; theta += angle[i]; } if(theta == a){ if(negitive){ return -(y/sqrt((x*x+y*y))); }else{ return (y/sqrt((x*x+y*y))); } }else{ //旋转的弧度超过了a,退回原来增加的角度,同时进入下一次迭代 theta -= angle[i]; x = orix; y = oriy; } } if(negitive){ return -(y/sqrt((x*x+y*y))); }else{ return (y/sqrt((x*x+y*y))); } } }该代码计算结果的精度可以达到10^-5次方,如果要提高精度,可以减小每次增加的弧度的最小值,例如将迭代每次增加的最小的弧度值设为 pi/65536

参考链接:

CORDIC算法入门:blog.csdn/liyuanbhu/article/details/8458769

CORDIC_百度百科:baike.baidu/item/CORDIC

本文标签: 函数方法