Swift CORDIC 算法给出不变的答案

标签 swift trigonometry

我试图在 Cordic wikipedia webpage 上翻译 MATLAB 语言

但是当我输入这些时:

print(cordic(beta: Double.pi/9, n: 20))
print(cordic(beta: Double.pi/8, n: 20))

我明白了

[-0.17163433840184755, 0.98516072489744066]
[-0.17163433840184755, 0.98516072489744066]

它总是给我一个不变的答案。为什么?我确定“角度”和“Kvalues”数组已正确计算。

代码如下:

import Foundation

var angles: [Double] = []

for i: Double in stride(from: 0, to: 27, by: 1) {
    angles.append(atan(pow(2, -i)))
}
var Kvalues: [Double] = []

for i: Double in stride(from: 0, to: 23, by: 1) {
    Kvalues.append(1/sqrt(abs(Double(1) + pow(2,-2 * i))))
    if i > 0 {
        Kvalues[Kvalues.count - 1] *= Kvalues[Kvalues.count - 2]
    }
}
func min(_ a: Int, _ b: Int) -> Int {
    return a > b ? b : a
}
func cordic(beta: Double, n: Int) -> [Double] {
    var beta1 = beta
    let Kn = Kvalues[min(n, Kvalues.count - 1)]
    var v: [Double] = [1,0]
    var poweroftwo: Double = 1
    var angle = angles[0]

    for j in 0 ..< n {
        let sigma: Double = beta < 0 ? -1 : 1
        let factor: Double = sigma * poweroftwo
        v = [v[0] - v[1] * factor, v[1] + v[0] * factor]
        beta1 -= sigma * angle
        poweroftwo /= 2
        angle = j + 2 > angles.count ? angle / 2 : angles[j + 2]
    }
    return [v[0] * Kn, v[1] * Kn]
}
print(cordic(beta: Double.pi/9, n: 20))
print(cordic(beta: Double.pi/8, n: 20))

最佳答案

不同的输入会得到相同的结果,因为

let sigma: Double = beta < 0 ? -1 : 1

beta应该是beta1,也就是局部变量 在循环中更新。

但即使在修复之后结果也不正确,那就是 由两个“off-by-one”索引错误引起。 algorithm description 中的数组是基于 1 的,而 Swift 数组是基于 0 的。所以

let Kn = Kvalues[min(n, Kvalues.count - 1)]
// should be
let Kn = Kvalues[min(n-1, Kvalues.count - 1)]

angle = j + 2 > angles.count ? angle / 2 : angles[j + 2]
// should be
angle = j + 1 >= angles.count ? angle / 2 : angles[j + 1]

应该为 i 定义 anglesKvalues 数组,范围从 0 到 ,包括 27。 23.

最后,您无需定义自己的 min 函数,因为 Swift 标准库中已有该函数。

将它们放在一起你的代码将是:

var angles: [Double] = []

for i: Double in stride(from: 0, through: 27, by: 1) {
    angles.append(atan(pow(2, -i)))
}
var Kvalues: [Double] = []

for i: Double in stride(from: 0, through: 23, by: 1) {
    Kvalues.append(1/sqrt(abs(Double(1) + pow(2,-2 * i))))
    if i > 0 {
        Kvalues[Kvalues.count - 1] *= Kvalues[Kvalues.count - 2]
    }
}

func cordic(beta: Double, n: Int) -> [Double] {
    var beta1 = beta
    let Kn = Kvalues[min(n-1, Kvalues.count - 1)]
    var v: [Double] = [1,0]
    var poweroftwo: Double = 1
    var angle = angles[0]

    for j in 0 ..< n {
        let sigma: Double = beta1 < 0 ? -1 : 1
        let factor: Double = sigma * poweroftwo
        v = [v[0] - v[1] * factor, v[1] + v[0] * factor]
        beta1 -= sigma * angle
        poweroftwo /= 2
        angle = j + 1 >= angles.count ? angle / 2 : angles[j + 1]
    }
    return [v[0] * Kn, v[1] * Kn]
}

这会产生很好的近似值:

print(cordic(beta: Double.pi/9, n: 20)) // [0.93969210812600046, 0.34202155184390554]
print(cordic(beta: Double.pi/8, n: 20)) // [0.92388022188807306, 0.38268176805806309]

确切的值是

print(cos(Double.pi/9), sin(Double.pi/9)) // 0.939692620785908 0.342020143325669
print(cos(Double.pi/8), sin(Double.pi/8)) // 0.923879532511287 0.38268343236509

关于Swift CORDIC 算法给出不变的答案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45110321/

相关文章:

arrays - 如何过滤结构数组?

swift - 如何在 init() 期间取消对象的初始化?

ios - 如何连接两个UITextView

java - 在自顶向下游戏中使用三角函数时遇到问题

math - 如何计算沿圆柱体切片的两点之间的 SVG 路径弧

ios - Firebase iOS -.queryOrdered().queryEqual(toValue : and child(). observeSingleEvent 之间有什么区别

swift - 为隐藏和显示密码创建一个通用类

c - alsa linux c程序输出的奇怪正弦波

java - 如何获得三角函数的用户友好值?

c++ - boost 区间算术和三角函数