Engee 文档
Notebook

CORDIC算法

本示例介绍了Julia编程语言中CORDIC算法的实现,用于计算三角函数(正弦和余弦)。 而不使用标准功能。

导言

CORDIC算法(来自坐标旋转数字计算机)是一种迭代数值方法,用于计算三角函数,双曲线和其他数学函数。 CORDIC最初是为导航系统开发的,在计算资源有限的情况下特别有用,因为它只使用加法,减法和移位,这些操作在硬件和软件上都能很好地工作。 在本例中,CORDIC用于计算给定角度的正弦和余弦值。

主要部分

安装和连接软件包

In [ ]:
import Pkg; Pkg.add("Printf")
In [ ]:
using Printf

功能 cordic

这是实现CORDIC算法的主要功能。 她的角度 alpha 以弧度和迭代次数为单位 iteration. 迭代次数会影响结果的准确性。 迭代次数越多,精度越高,但计算时间也越长。

In [ ]:
function cordic(alpha, iteration = 24)
    # 如果角度大于2π,则在确定新标志时可能会出现标志失败。
    newsgn = isodd(Int(floor(alpha / 2π))) ? 1 : -1
    
    # 使角度范围[-π/2,π/2]
    alpha < -π/2 && return newsgn * cordic(alpha + π, iteration)
    alpha > π/2 && return newsgn * cordic(alpha - π, iteration)

    # 预先计算的反正切2^(-j)的表,其中j=0,1,2,。..
    angles = [
        0.78539816339745,   0.46364760900081,   0.24497866312686,   0.12435499454676,
        0.06241880999596,   0.03123983343027,   0.01562372862048,   0.00781234106010,
        0.00390623013197,   0.00195312251648,   0.00097656218956,   0.00048828121119,
        0.00024414062015,   0.00012207031189,   0.00006103515617,   0.00003051757812,
        0.00001525878906,   0.00000762939453,   0.00000381469727,   0.00000190734863,
        0.00000095367432,   0.00000047683716,   0.00000023841858,   0.00000011920929,
        0.00000005960464,   0.00000002980232,   0.00000001490116,   0.00000000745058]

    # 缩放因子Kn的表,在最后考虑
    Kvalues = [
        0.70710678118655,   0.63245553203368,   0.61357199107790,   0.60883391251775,
        0.60764825625617,   0.60735177014130,   0.60727764409353,   0.60725911229889,
        0.60725447933256,   0.60725332108988,   0.60725303152913,   0.60725295913894,
        0.60725294104140,   0.60725293651701,   0.60725293538591,   0.60725293510314,
        0.60725293503245,   0.60725293501477,   0.60725293501035,   0.60725293500925,
        0.60725293500897,   0.60725293500890,   0.60725293500889,   0.60725293500888]

    # 我们根据迭代次数选择缩放级别的值。
    Kn = Kvalues[min(iteration, length(Kvalues))]  

    # 向量的初始值为[cos(0),sin(0)] = [1, 0]
    v = [1, 0]  
    poweroftwo = 1  # 2的幂,2^0=1,随着每次迭代而变化
    angle = angles[1]  # 当前旋转角度
    
    # CORDIC的主要迭代周期
    for j = 0:iteration-1
        if alpha < 0
            sigma = -1  # 逆时针转动
        else
            sigma = 1   # 顺时针转动
        end
        
        factor = sigma * poweroftwo  # 旋转矩阵的系数

        # 角度atan(2^(-j))的旋转矩阵,以CORDIC形式编写
        R = [1 -factor
             factor  1]

        # 将向量v乘以矩阵R(旋转向量)
        v = R * v  

        # 为下一次迭代更新剩余角度的值
        alpha -= sigma * angle 

        # 移动到下一个两次方
        poweroftwo /= 2  

        # 为下一次迭代更新角度
        if j + 2 > length(angles)
            angle /= 2  # 如果桌子结束,将角度减少一半。
        else
            angle = angles[j + 2]  # 否则,我们从表中取以下角度
        end
    end

    # 我们应用一个缩放因子来获得真实值。
    v .*= Kn
    return v  # 我们返回[cos(alpha),sin(alpha)]
end
Out[0]:
cordic (generic function with 2 methods)

功能 test_cordic

此函数用于检查算法的操作。 它输出各种角度的正弦和余弦值(以度和弧度为单位),并将它们与内置的Julia函数进行比较。

In [ ]:
function test_cordic()
    println("   x      sin(x)        Δsin         cos(x)        Δcos ")

    # 以15°为增量检查-90°至+90°的角度
    for θ in -90:15:90 
        # 将度数转换为弧度并运行CORDIC函数
        cosθ, sinθ = cordic(deg2rad(θ))

        # 我们以以下格式打印值:角度,sin,正弦误差,余弦误差
        @printf("%+05.1f°  %+.8f (%+.8f) %+.8f (%+.8f)\n",
           θ, sinθ, sinθ - sind(θ), cosθ, cosθ - cosd(θ))
    end

    println("\nx(rad)sin(x)Δsin cos(x)Δcos ")

    # 检查弧度中的某些角度
    for θr in [-9, 0, 1.5, 6]
        cosθ, sinθ = cordic(θr)
        @printf("%+3.1f    %+.8f (%+.8f) %+.8f (%+.8f)\n",
           θr, sinθ, sinθ - sin(θr), cosθ, cosθ - cos(θr))
    end
end
Out[0]:
test_cordic (generic function with 1 method)
In [ ]:
test_cordic()
   x      sin(x)        Δsin         cos(x)        Δcos 
-90.0°  -1.00000000 (+0.00000000) -0.00000007 (-0.00000007)
-75.0°  -0.96592585 (-0.00000003) +0.25881895 (-0.00000009)
-60.0°  -0.86602545 (-0.00000005) +0.49999992 (-0.00000008)
-45.0°  -0.70710684 (-0.00000006) +0.70710672 (-0.00000006)
-30.0°  -0.49999992 (+0.00000008) +0.86602545 (+0.00000005)
-15.0°  -0.25881895 (+0.00000009) +0.96592585 (+0.00000003)
+00.0°  -0.00000007 (-0.00000007) +1.00000000 (-0.00000000)
+15.0°  +0.25881895 (-0.00000009) +0.96592585 (+0.00000003)
+30.0°  +0.49999992 (-0.00000008) +0.86602545 (+0.00000005)
+45.0°  +0.70710684 (+0.00000006) +0.70710672 (-0.00000006)
+60.0°  +0.86602545 (+0.00000005) +0.49999992 (-0.00000008)
+75.0°  +0.96592585 (+0.00000003) +0.25881895 (-0.00000009)
+90.0°  +1.00000000 (-0.00000000) -0.00000007 (-0.00000007)

x(рад)    sin(x)        Δsin         cos(x)        Δcos 
-9.0    -0.41211842 (+0.00000006) -0.91113029 (-0.00000003)
+0.0    -0.00000007 (-0.00000007) +1.00000000 (-0.00000000)
+1.5    +0.99749499 (+0.00000000) +0.07073719 (-0.00000002)
+6.0    -0.27941552 (-0.00000002) +0.96017028 (-0.00000001)

结论

在这个例子中,我们研究了Julia中CORDIC算法的实现,用于计算正弦和余弦的值。 该算法允许您仅依靠简单的算术运算来避免使用复杂的运算。 这使得它在计算能力有限的系统中特别有用。 我们还对实现进行了测试,将其与内置函数进行了比较,并确保结果与参考结果接近,这证实了实现的正确性。

该示例是使用[Rosetta代码]的材料开发的(https://rosettacode.org/wiki/CORDIC