0
点赞
收藏
分享

微信扫一扫

基于CORDIC算法实现sin()函数(C语言)

犹大之窗 2022-04-19 阅读 65

基于CORDIC算法实现sin()函数(C语言)

CORDIC算法简介:

CORDIC(Coordinate Rotation Digital Computer)坐标旋转数学计算是数学与计算机技术交叉之后所产生的一中机器学习算法,其广泛应用于解决计算机的数学计算问题中。发展到现在,CORDIC算法及其扩展算法大致有三种计算模式:圆周旋转模式、线性旋转模式和双曲线旋转模式,分别用来实现不同的数学运算。

简单地说,CORDIC利用近似逼近的思想,将计算机中三角函数、开根号、求对数等复杂运算,转化为简单的加减和移位操作。

(1)算法原理

通过将原坐标轴转换为变换后的坐标轴后,计算转角
在这里插入图片描述

(2)算法理论分析

假设在原坐标系中,A的坐标为(X,Y),记在转换后的坐标中A的坐标为(X’,Y’).即:
X = O D , Y = A D X=OD,Y=AD X=OD,Y=AD
(2.1)求X’

从图中可以看出:
X ′ = O E + B E X'=OE+BE X=OE+BE
又因为
C D = B E CD=BE CD=BE
所以
X ′ = O E + C D , O E = X × cos ⁡ ( θ ) X'=OE+CD,OE=X\times\cos(\theta) X=OE+CD,OE=X×cos(θ)
又因为
B E = C D = Y × sin ⁡ ( θ ) BE=CD=Y\times\sin(\theta) BE=CD=Y×sin(θ)
最终得出:
X ′ = O E + B E = X × cos ⁡ ( θ ) + Y × sin ⁡ ( θ ) (1) X'=OE+BE=X\times\cos(\theta)+Y\times\sin(\theta)\tag{1} X=OE+BE=X×cos(θ)+Y×sin(θ)(1)
(2.2)求Y’

由图可以很容易看出
Y ′ = A C − B C Y'=AC-BC Y=ACBC

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHlPLvEO-1650360946953)(C:\Users\pc\AppData\Roaming\Typora\typora-user-images\image-20220419144542247.png)]

又因为
A C = A D × cos ⁡ ( θ ) , B C = D E = O D × sin ⁡ ( θ ) AC=AD\times\cos(\theta),BC=DE=OD\times\sin(\theta) AC=AD×cos(θ),BC=DE=OD×sin(θ)
有上述所得:
A C = Y × cos ⁡ ( θ ) , B C = D E = X × sin ⁡ ( θ ) AC=Y\times\cos(\theta),BC=DE=X\times\sin(\theta) AC=Y×cos(θ),BC=DE=X×sin(θ)
最终得出:
Y ′ = A B = A C − B C = Y × cos ⁡ ( θ ) − X × sin ⁡ ( θ ) (2) Y'=AB=AC-BC=Y\times\cos(\theta)-X\times\sin(\theta)\tag{2} Y=AB=ACBC=Y×cos(θ)X×sin(θ)(2)
由以上可以得出:
{ X ′ = X × cos ⁡ ( θ ) + Y × sin ⁡ ( θ ) Y ′ = Y × cos ⁡ ( θ ) − X × sin ⁡ ( θ ) \left\{ \begin{array}{lr} X'=X\times\cos(\theta)+Y\times\sin(\theta)\\ Y'=Y\times\cos(\theta)-X\times\sin(\theta) \end{array} \right. {X=X×cos(θ)+Y×sin(θ)Y=Y×cos(θ)X×sin(θ)
对等式①与等式②同时提取
cos ⁡ ( θ ) \cos(\theta) cos(θ)
得到:
{ X ′ = cos ⁡ ( θ ) × ( X × + Y × sin ⁡ ( θ ) ) Y ′ = cos ⁡ ( θ ) × ( Y × − X × sin ⁡ ( θ ) ) \left\{ \begin{array}{lr} X'=\cos(\theta)\times(X\times+Y\times\sin(\theta))\\ Y'=\cos(\theta)\times(Y\times-X\times\sin(\theta)) \end{array} \right. {X=cos(θ)×(X×+Y×sin(θ))Y=cos(θ)×(Y×X×sin(θ))
忽略cos()对于X’与Y’的影响,得到“伪旋公式”:
{ X ′ = X × + Y × sin ⁡ ( θ ) Y ′ = Y − X × sin ⁡ ( θ ) \left\{ \begin{array}{lr} X'=X\times+Y\times\sin(\theta)\\ Y'=Y-X\times\sin(\theta) \end{array} \right. {X=X×+Y×sin(θ)Y=YX×sin(θ)
伪旋公式:仅仅实现了正确的角度旋转,但向量模值变为了原来数值的
1 cos ⁡ ( θ ) \frac{1}{\cos(\theta)} cos(θ)1
使用CORDIC方法:

使得
tan ⁡ ( θ ) = 2 i , i ∈ − N ∗ \tan(\theta)=2^i,i\in-N^* tan(θ)=2iiN

则“伪旋公式”进一步简化为:
{ X ′ = X × + Y × 2 i Y ′ = Y − X × 2 i \left\{ \begin{array}{lr} X'=X\times+Y\times2^i\\ Y'=Y-X\times2^i \end{array} \right. {X=X×+Y×2iY=YX×2i
该式子已经仅剩下加减和移位运算了。

以下是
tan ⁡ ( θ ) = 2 i , i ∈ − N ∗ \tan(\theta)=2^i,i\in-N^* tan(θ)=2iiN
所得的相关角度和正切值的对应表。

img

任意旋转角度θ,都可以由上表中的大小不同的θ进行多次旋转得到。CORDIC正是利用这一点,将θ角度的旋转分解为从大到小、逐次逼近真实旋转角度的一组旋转,而这些旋转的实现又都可以由加减和移位运算来完成。θi可以预先制成表格,供计算机查找使用。

(2)程序代码

#include <iostream>
#include <math.h>
#include <iomanip>   //设置必备的头文件
using namespace std;

void my_atan1(double A); //用于0~180 sin求解 
void my_atan2(double A); //用于180~360 sin求解
 
double S_C;

//主函数入口 
int main()
{	
    int	x;
    cout<<"enter a number:"<<endl;
	cin>>x;	
	//角度大于0 
	if(x>=0){
		x=x%360; 
	}
	//角度小于0 
	while(x<0){
		x+=360;
	}
	
	if(x>=0 && x<=90){
		my_atan1(x); //0~90
	}
	else if(x>90 && x<=180){
		my_atan1(180-x); //90~180
	}
	else if(x>180 && x<=270){
	    my_atan2(x-180);
	}else{
		my_atan2(360-x);
	}
	cout<<setiosflags(ios::fixed)<<setprecision(2);
	//cout<<"cos:"<< S_C[0] <<endl;
	cout<<"sin:"<<S_C<< endl;
	system("pause");
	return 0;
}

//角度属于0~180之间的角度数值求解 
void my_atan1(double A)
{	
	//迭代设置 
	double angle[]={45, 26.565, 14.036, 7.125, 3.5763,
                    1.7899, 0.8952, 0.4476, 0.22381,	
                    0.1119, 0.0559, 0.028, 0.01399		// 12 time
                   };
	double x=1;
	double y=0;
	double k=0.60723;//0.63664;
	int i=0;
	double x_new,y_new;
	//double angle=45;
	//进行迭代 
	for(i=0;i<12;i++)
	{
		angle[i]=(angle[i]/45)*pow(2,20);
	}
	A=(A/45)*pow(2,20);

	for(i=0;i<12; i++)
	{
		if(A>0)
		{
			x_new=(x-y*(1/pow(2,i)));
			y_new=(y+x*(1/pow(2,i)));
			x=x_new;
			y=y_new;
			A-=angle[i];
		}
		else{
			x_new=(x+y*(1/pow(2,i)));
			y_new=(y-x*(1/pow(2,i)));
			x=x_new;
			y=y_new;
			A+=angle[i];
		}
		//按对分查找方法寻找角度的近似值
		//angle/=2;
	}

	//S_C[0] = x * k;
	S_C=y*k;
}

//角度属于180~360之间的角度数值求解 
void my_atan2(double A)
{
	//迭代参数设置 
	double angle[]={45, 26.565, 14.036, 7.125, 3.5763,
                    1.7899, 0.8952, 0.4476, 0.22381,	
                    0.1119, 0.0559, 0.028, 0.01399		// 12 time
                   };
	double x=1;
	double y=0;
	double k=0.60723;//0.63664 0.60723;
	int i=0;
	double x_new,y_new;
	//double angle=45;
	//进行迭代 
	for(i=0;i<12;i++)
	{
		angle[i]=(angle[i]/45)*pow(2, 20);
	}
	A=(A/45)*pow(2,20);

	for(i=0;i<12;i++)
	{
		if(A>0)
		{
			x_new=(x-y*(1/pow(2,i)));
			y_new=(y+x*(1/pow(2,i)));
			x=x_new;
			y=y_new;
			A-=angle[i];
		}
		else{
			x_new=(x+y*(1/pow(2,i)));
			y_new=(y-x*(1/pow(2,i)));
			x=x_new;
			y=y_new;
			A+=angle[i];
		}
		//按对分查找方法寻找角度的近似值
		//angle/= 2;
	}

	//S_C[0]=x*k;
	S_C=-y*k;
}

举报

相关推荐

0 条评论