发现与发明 › 20 世纪

CORDIC1959

algorithm for computing trigonometric and hyperbolic functions

CORDIC,也称为Volder算法,是一个可以计算三角函数,简单且有效率的算法,可以在任意进制下运算,一般会每次计算一位数字。因此CORDIC属于逐位计算(Digit-by-digit)方法中的一个例子。

摘自维基百科「CORDIC」,CC BY-SA 4.0

类型
近似算法
发现 / 发明时间
1959 年
发现者 / 提出者
Jack E. Volder
命名来源
自转

百科正文

CORDIC算法还有其他的名称,像是圆形CORDIC (Jack E. Volder)、线性CORDIC、双曲线CORDIC(John Stephen Walther)、及泛用双曲线CORDIC(GH CORDIC, Yuanyong Luo et al.)。用类似的方式也可以计算双曲函数、平方根、乘法、除法、指数及对数等。

CORDIC和一些名为“伪乘法”(pseudo-multiplication)、“伪除法”(pseudo-division)及factor combining的方法,常用在没有乘法器的应用(像是简单的微控制器以及FPGA),其中会用到的运算是加法、减法、位元移位及查找表。这些算法可归类在“移位和相加”(shift-and-add)算法中。在计算机科学中,若CPU没有硬件的乘法器,常会用CORDIC来实现浮点数运算。

历史

英国数学家亨利·布里格斯早在1624年时就已发现此算法,后来Robert Flower也在1771年时发现,不过后来是因为低复杂度的有限状态CPU,才针对CORDIC作较进一步的最佳化。

CORDIC是在1956年问世,是由康维尔空气电子部门的Jack E. Volder发现,一开始是因为要取代B-58轰炸机导航电脑上面的类比式解角器(resolver),更换成更准确而实时的数位方案。因此,有时也会将CORDIC称为数位解角器(digital resolver)。

Volder的研究,是因为1946年版CRC化学和物理手册中的公式而得到灵感: (公式略)

其中 φ 是使 tan(φ)=2⁻ⁿ 成立的值,且 (公式略)。

他的研究最后产生了一个内部的技术报告,提到用CORDIC算法来求解正弦及余弦函数,以及一个实现此功能的原型电脑。报告中也提到用修改版的CORDIC算法计算双曲函数、坐标旋转、对数及指数的可能性。用CORDIC来进行乘法和除法运算的想法也是在此时形成。依照CORDIC算法的原则,Volder的同事Dan H. Daggett发展了在二进制以及二进码十进数(BCD)之间转换的算法。

应用

CORDIC用简单的移位和相加运算来处理像是三角函数、双曲函数、对数函数、实数及复数乘法、除法、方根计算、线性系统求解、特征值估测、奇异值分解、QR分解等。因此,CORDIC可以用在许多的应用中,像是信号处理、影像处理、通讯系统、机器人学及三维计算机图形等。

硬件

若没有硬件乘法器的话,CORDIC一般会比其他算法要快很多,若是用FPGA或ASIC的话,使用的逻辑门也会少很多。

CORDIC是FPGA开发应用程序(像是Xilinx的Vivado)中的标准半导体IP核,而不是使用特殊函数的幂级数实现,其原因是CORDIC IP的通用性,CORDIC可以计算许多不同的函数,而为特定函数开发的乘法器只能计算特定的函数。

另一方面,若有硬件乘法器(例如DSP),查表法及幂级数会比CORDIC快很多。近年来,CORDIC算法常用在生医应用中,尤其是用FPGA实现的应用。

使用泰勒级数的问题是此方法可以产生小的绝对误差,但其中没有良态的相对误差。其他多项式近似法,例如Minimax近似算法,可以同时控制这二种的误差。

软件

在CPU只有整数运算的古老系统中,会将CORDIC放在其IEEE 754函式库的一部分。现代的通用CPU已有浮点运算暂存器,也有加法、减法、乘法、除法、三角函数、平方根、一般对数、自然对数等,几乎没有用到CORDIC的场合。只有一些有特殊安全性或是时间要求的应用程序才会用到CORDIC。

运作模式

旋转模式

CORDIC可以用来计算许多不同的函数。以下说明如何在旋转模式(rotation mode)下的CORDIC计算角度的正弦函数和余弦函数,假设角度以弧度的定点格式表示。要找到一个角度 β 的正弦函数和余弦函数,可以在单位圆上找到对应角度的y坐标和坐标。利用CORDIC,会从以下的向量 v₀ 开始: (公式略)

在第一次的迭代时,向量逆时针转45°,得到向量 v₁。接着继续的迭代,每一次的角度渐渐变小,旋转方向可能顺时针,也可能逆时针,直到得到想要的角度为止。每一次的角度为 (公式略),其中 i=0,1,2,…。

若以更正式的方式表示,每一次的迭代就是一次旋转,也就是将向量 vᵢ 乘以旋转矩阵 Rᵢ: vᵢ₊₁=Rᵢvᵢ.

  • 旋转矩阵为 (公式略)
  • 利用以下两个三角恒等式: (公式略)
  • 旋转矩阵变成 (公式略)
  • 旋转向量 vᵢ₊₁=Rᵢvᵢ 就会变成下式 (公式略)

其中 xᵢ 和 yᵢ 是 vᵢ 的分量,若将角度 γ ᵢ 限制在使 tan(γ ᵢ)=± 2⁻ⁱ 的值,和tangent的乘法就以变成乘(或除)2的幂次,在数位电脑硬件中可以快速的用位元右移或左移来计算。因此上法会变成 (公式略)

其中 (公式略)

且 σ ᵢ 是用来判断旋转方向的。若角度 γ ᵢ 为正,则 σ ᵢ 为+1,否则则为−1。

所有的 Kᵢ 因子可以在迭代过程中忽略,最后再一次乘以 K(n) 因子即可: (公式略)

此数可以事先计算好存在表格中,若迭代次数是固定的,只需计算一个常数且储存即可,甚至此修正也可以事先进行,将常数先乘以 v₀,可以节省一次乘法。另外,可以注意到 K=lim _(n→ ∞)K(n)≈ 0.6072529350088812561694

因此可以简化算法的复杂度。有些应用会避免修正 K,因此此算法本身会带一个增益 A: (公式略)

在够多次的迭代后,向量的角度会接近想要的角度 β。以一般的应用来说,40次的迭代(n = 40)已可以有小数10位的精度。

唯一未解决的问题是判断每一次迭代要顺时针旋转或逆时针旋转(选择 σ 的值)。这可以记录每一次旋转的角度,从还需要旋转的角度中减去此一角度,会得到下一个还需要旋转的角度 β。若 β ₙ₊₁ 为正,需要顺时针旋转,否则,就需要逆时针旋转: β ₀=β

β (公式略)

γ γ ₙ 的值需要事先计算且记录下来。不过若是小角度,根据小角度近似,在定点数下可得 (公式略),因此可以节省储存用的空间。

如以上所述,角度 β 的正弦函数为其y坐标,余弦函数为其x坐标。

向量模式

上述旋转模式的算法,是旋转原来位在x轴上的单位向量。但此算法可以用来旋转角度在− π /2 及 π /2 之间的任意向量,旋转的方向则依 β ᵢ 的正负号决定。

向量模式下的算法和旋转模式略有不同。其启始向量的x坐标要为正值,y坐标则为任意值。持续转动的目的是将向量旋转到x轴(因此y坐标为0)。每一步里的旋转方向会由y的值决定。 β ᵢ 的最终值包括了总旋转角度。x的最终值是原向量的大小,再乘以K。因此,可以看出向量模式可以进行直角坐标到极坐标的转换。

实现

Java的Math类别中有scalb(double x,int scale)方法可以实现二进制的移位,C语言有ldexp函数,x86处理器有fscale浮点运算。

软件范例(Python)

硬件范例

实现CORDIC需要的逻辑门大约和乘法器相当,两者都是用位元移位和加法所组合的。要选择乘法器或是CORDIC会随应用而定。若复数以其实部和虚部表示(直角坐标),复数乘法会需要进行四次的乘法。但若复数以极坐标表示,只要一个CORDIC即可处理,这更适合用在其乘积的量值不重要的应用(例如将向量和单位圆上的向量相乘的情形)。在数位下转换器之类的通讯相关电路中,常会用到CORDIC。

双重迭代CORDIC

在Vladimir Baykov的二篇文献中,曾经提到用“双重迭代”(double iterations)来实现反正弦函数、反余弦函数、自然对数、指数函数以及双曲函数。双重迭代中的作法和传统的CORDIC算法不同,传统的CORDIC算法中,迭代变数会在每次迭代时加一。但在双重迭代中,迭代变数会先重复一次,然后才加一。因此双重迭代CORDIC算法的迭代变数会是 i=0,0,1,1,2,2…,而传统CORDIC算法的迭代变数是 i=0,1,2…。双重迭代法保证方法的收敛,不过其引数的有效范围会变化。

针对 R 进制数字系统中,通用的CORDIC收敛问题,可以证明针对正弦、余弦及反正切函数,每一个i(i = 0或1到n,其中n是位数)进行 R-1 次迭代就可以保证收敛。若是自然对数、指数、双曲正弦、双曲余弦及双曲反正切函数,每一个i需要进行 R 次迭代。若是反正弦函数及反余弦函数,每一个i需要进行2 R-1 次的迭代。

若是双曲反正弦及双曲反余弦函数,每一个i需要进行2R次的迭代。

相关算法

CORDIC属于“移位及加法”(shift-and-add)的算法,就像Henry Briggs文献提到的对数和指数算法一样。BKM算法也是可以计算许多基本函数的移位及加法算法,是复数平面下对数和指数算法的推广。BKM可以计算实数角度 x (以弧度表示)的正弦和余弦,其方式是计算 0+ix 的指数,也就是 cis (x)=cos(x)+isin(x)。BKM算法比CORDIC要复杂一些,但其优点是不需考虑比例因子(K)。

以上内容摘自维基百科「CORDIC」,按 CC BY-SA 4.0 使用,去掉了参考文献、外部链接等尾部小节,公式改写成了纯文本。全文、配图和出处见原文。

同一学科、时间相近的发现与发明