介紹:
最近看到這篇文章有對Accelerate框架有一個介紹,自己也按照作者給的思路整理了一遍,也算是對這一框架的一個重新的回顧和學習,在以前研究AR先關只是的時候有接觸到這個框架,贊具體裡面的東西沒有好好的實踐一下,文章中有一些關於向量和矩陣運算的實際的Swift例子。可以簡單的看一下。
Introduction to the Accelerate Framework in Swift
關於這個框架和文章其實在前面介紹iOS框架系列文章的時候有提過(第一篇),對這個框架有不清楚是做什麼的可以翻翻我以前總結的文章。
由於下面的運算都是些向量和矩陣的運算,要是不清楚他們的概念和運算規則的可以看下面,先了解清楚再往下看,這些具體的內容在專案當中其實還是會用到的,比如說視訊編碼處理、AR等等。
Accelerate
使用之前請先匯入這兩個框架:
NOTE: 下面所有的例子全都是在 Playground 執行驗證
import UIKit import Accelerate import simd
1、cblas_saxpy
函式cblas_saxpy(_:_:_:_:_:_:)是一個計算常數乘以一個向量加上一個向量的函式,具體的使用看下面的例子:
var x:[Float] = [1,2,3] var y:[Float] = [4,5,6] cblas_saxpy(3, 10, &x, 2, &y, 2)
具體的驗證結果和詳細的函式引數說明我們會在下面展示,大家可以先看上面給出的函式的說明推導一下結果:
2、cblas_sdot 這個函式能幫助我們計算出兩個向量的數量積: ∑ a[i] * b[i]
y = [4,5,6] /// x*y = (1*4)+(2*5)+(3*6) = 32 /// 這個函式的具體的引數可以參考上面 cblas_sdot(3, &x, 1, &y, 1)
3、sgesv_ 這個函式可以幫我們解方程,比如下面的三元三次方程,具體的驗證你可以自己嘗試一下,瞭解一下函式的引數的意義,我們已經驗證過就不再重複結果。
/// 下面我們解一個三元方程 /// 7x+5y-3z = 16 /// 3x-5y+2z = -8 /// 5x+3y-7z = 0 typealias LAInt = __CLPK_integer var A:[Float] = [ 7, 3, 5, /// x 5, -5,3, /// y -3,2,-7 /// z ] var b:[Float] = [16,-8,0] /// 定義要解的是一個幾元方程 let equations = 3 /// 方程的個數 var numberOfEquations:LAInt = 3 var columnsIntA:LAInt = 3 var elementsIntB:LAInt = 3 /// 解的個數 var bSolutionCount:LAInt = 1 /// 驗證是否計算有問題 var outputOk:LAInt = 0 /// [0,0,0] var pivot = [LAInt](repeating: 0, count: equations) /// 引數定義(按順序):求解的線性方程個數、解的個數、係數矩陣A、 /// 矩陣A的列數、排列矩陣、係數向量B、向量B的列數、輸出值。 sgesv_(&numberOfEquations, &bSolutionCount, &A, &columnsIntA, &pivot, &b, &elementsIntB, &outputOk) /// outputOk == 0 說明一切計算正確 outputOk /// 這個結果就是我們想要的答案 [1, 3, 2] b
simd + vecLib + vDSP
具體的這三個框架的內容文章中有介紹過,我們這裡主要的還是驗證和實踐一下里面的例子,看下面的程式碼。
1、矩陣的加法運算,看下面的例子,注意下面的不是向量的加法,留意區別不要混淆,程式碼簡單我直接截圖順便看驗證結果:
2、vvfabsf 求絕對值的運算,程式碼如下:
/// fabs 求絕對值 func floats(_ n:Int32) -> [Float]{ return [Float] (repeating: 0, count: Int(n)) } var count:Int32 = 4 var aAbsoAbsolute = floats(count) var c:[Float] = [-1,-2,-3,-4] vvfabsf(&aAbsoAbsolute, &c, &count) /// [1,2,3,4] aAbsoAbsolute
3、vvintf 小數取整求絕對值
c = [9.987,6.576,-3.345,-4.9] var bAbsoAbsolute = floats(count) vvintf(&bAbsoAbsolute, &c, &count) /// [9, 6, -3, -4] bAbsoAbsolute
4、sqrtf 開平方根
/// sqrt 開平方根 sqrtf() c = [25,16,9,4] var cAbsoAbsolute = floats(count) vvsqrtf(&cAbsoAbsolute, &c, &count) /// [5, 4, 3, 2] cAbsoAbsolute
5、分數取逆 這時候是分母和分子互換位置在做計算得來的
/// 分數取逆 這時候是分母和分子互換位置在做計算得來的 var d:[Float] = [1/3,1/5,3/9,4/2] var dAbsoAbsolute = floats(count) vvrecf(&dAbsoAbsolute, &d, &count) /// [3, 5, 3, 0.5] dAbsoAbsolute
6、vDSP_vdist 這個例子其實也很有趣的,具體的例子說明可以參考最上面文章的最後一個例子,我們直接看程式碼和驗證的結果,程式碼裡面有比較詳細的說明,還是值得一看的,能幫助我們回憶鞏固一些知識點:
var points:[CGPoint] = [ CGPoint(x: 0, y: 0), CGPoint(x: 0, y: 10), CGPoint(x: 0, y: 20), CGPoint(x: 0, y: 30), CGPoint(x: 0, y: 40), CGPoint(x: 0, y: 50), CGPoint(x: 0, y: 60), CGPoint(x: 0, y: 70), CGPoint(x: 0, y: 80) ] let path = UIBezierPath() path.move(to: points[0]) // IMP: Remove the space between the < and points for i in 1 ..< points.count { path.addLine(to: points[i]) } var xs = points.compactMap { (point) -> Float? in return Float(point.x) } var ys = points.compactMap { (point) -> Float? in return Float(point.y) } var distance:[Float] = [Float](repeating: 0, count: points.count) vDSP_vdist(&xs, 1, &ys, 1, &distance,1,vDSP_Length(points.count)) /// 遍歷 distance.map {$0} /// 順便幫忙在加深一下對 reduce 函式的理解 /// 給一個初始值 然後對集合的每一個元素進行操作 distance.reduce(0, +) let initialResult:Float = 0 var reduceResult = distance.reduce(initialResult) { (tempResult,element) -> Float in return tempResult + element } reduceResult
下面是上面例子的結果驗證: