在 Swift 中使用 Accelerate 的一般原则
我发现首先尝试将您的代码从使用 for 循环的幼稚实现转换为映射很有帮助。如果您的代码被构造为使用地图,那么切换到加速变得非常容易,因为您已经解决了将算法结构化为矢量化操作的问题。
for 循环映射
let array: [Int] = [1, 2, 3, 4]
let array2 = [Int]()
for value in array {
array2 = value * 2
}
let array: [Int] = [1, 2, 3, 4]
array.map({ (value: Int) -> Int in
return value * 2
})
在相等大小的数组上操作版本
如果你发现要枚举两个或多个相同大小的数组那么上面可以结合map和enumerate
let alphas: [Double] = betas.enumerate().map({ (index: Int, beta: Double) -> Double in
return beta * phis[index]
})
设置用于 Accelerate 的数组
使用 Accelerate 的方式并不总是很明显,特别是 UnsafePointer 和 UnsafeMutablePointer 语法。这基本上是不必要的。
var alphaLowers = [Double](count: elementDelays.count, repeatedValue: 0)
vDSP_vmulD(&alphas, 1, &x_ns, 1, &alphaLowers, 1, UInt(elementDelays.count))
所以 Swift 避免了 malloc 和 free 的麻烦,它允许您创建一个自动内存管理对象,然后简单地将它与 & 号一起传递。我提到这一点是因为它避免尝试将对象包装在 UnsafeMutablePointer<Double>(alphaLowers) 中。
复数
我想做的大部分事情都依赖于涉及复数的运算。因此,要创建一个可以在 Accelerate 中使用的对象,您可以尝试以下操作。
var reals = [Double](count: 100, repeatedValue: 0)
var imaginaries = [Double](count: 100, repeatedValue: 0)
var complexNumbers = DSPDoubleSplitComplex(realp: &reals, imagp: &imaginaries)
复杂的exp()
我没有找到与 exp 等效的 Accelerate,但您可以使用欧拉方法分解这些值并对实数和虚数执行必要的操作,如下所示,使用 Complex Swift 库。
public func exp<T:RealType>(z:Complex<T>) -> Complex<T> {
let r = T.exp(z.re)
let a = z.im
return Complex(r * T.cos(a), r * T.sin(a))
}
我还没有找到避免这个问题的好方法,所以我实际上是在不使用 Accelerate 的情况下执行此步骤。只需将虚部取反即可计算复共轭。