移动周分享-第60期

加速库在数学运算中的使用

除了加减乘除外还有好多好多数学运算需要我们处理,但我们很多都没有用到,感觉low爆了

Apple:加速框架文档

Any time you’ve got to make some numbers happen, it’s probably worth it to consider using Accelerate

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 模拟随机数据
var doubles = (0...10000).map {_ in Double(arc4random()%10000)}
// 求和
// 常见的加法求和
let reduceSum = doubles.reduce(0) { $0+$1 }
// Accelerate 封装
let accSum = sum(doubles)
// 求最大值(最小值也一样)
let maxOfArr = max(doubles)
let maxOfArr2 = doubles.maxElement
// let maxOfArr2 = doubles.sort(>).first
// 平均值,哈哈大数据统计,可以测试准确率
let meanValue = mean(doubles)
let meanValue2 = doubles.reduce(0) { $0 + $1/Double(doubles.count) }
meanValue2
// 向量加减乘积
let vector1 = [2,4,5] as [Double]
let vector2 = [3,5,2] as [Double]
let sumArrs = add(vector1, y: vector2)

耗时上对比是不是reduce,map等系统的高阶函数被“加速库”秒了,但使用上貌似reduce,map是比较灵活的

1
2
let newReduceSum = (0...1000).reduce(0) { $0+$1 }
newReduceSum

其他计算的一点的应用

函数混合示例: 使用中文变量😄

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
let 函数点阵密度 = 64
let 频率1 = 4.0
let 相位1 = 0.0
let 幅度1 = 1.0
let 正弦函数1 = (0..<函数点阵密度).map {
幅度1 * sin(2.0 * M_PI / Double(函数点阵密度) * Double($0) * 频率1 + 相位1)
}
let 频率2 = 1.0
let 相位2 = M_PI / 2.0
let 幅度2 = 2.0
let 正弦函数2 = (0..<函数点阵密度).map {
幅度2 * sin(2.0 * M_PI / Double(函数点阵密度) * Double($0) * 频率2 + 相位2)
}
let 频率3 = 10.0
let 相位3 = M_PI / 3.0
let 幅度3 = 4.0
let 正弦函数3 = (0..<函数点阵密度).map {
幅度3 * sin(2.0 * M_PI / Double(函数点阵密度) * Double($0) * 频率3 + 相位3)
}
let 新函数1 = add(正弦函数1, y: 正弦函数2)
let 新函数2 = add(新函数1, y: 正弦函数3)
// Xcode 分栏查看图形排布,尤其是新函数的图形
新函数1.forEach { XCPlaygroundPage.currentPage.captureValue($0, withIdentifier:"新函数1") }
新函数2.forEach { XCPlaygroundPage.currentPage.captureValue($0, withIdentifier:"新函数2") }
正弦函数2.forEach { XCPlaygroundPage.currentPage.captureValue($0, withIdentifier:"正弦函数2") }
正弦函数1.forEach { XCPlaygroundPage.currentPage.captureValue($0, withIdentifier:"正弦函数1") }

傅里叶变换通俗篇讲解

1
2
3
// 查看图像发现‘新函数2’左右有三对波峰,得出它由三个正弦波组成(可对应得出振幅、频率及相位)
let 快速傅里叶转换 = fft(新函数2)
快速傅里叶转换.forEach { XCPlaygroundPage.currentPage.captureValue($0, withIdentifier:"快速傅里叶转换") }

矩阵计算

很多图像处理是根据矩阵做处理的,像素越大,处理性能要求越高

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 简单矩阵示例
// ⎛ 1 2 ⎞ ⎛ 3 2 ⎞ ⎛ 5 6 ⎞
// ⎢ ⎟ * ⎢ ⎟ = ⎢ ⎟
// ⎝ 3 -4 ⎠ ⎝ 1 2 ⎠ ⎝ 5 -2 ⎠
let A = Matrix([[1, 2], [3, -4]])
let B = Matrix([[3, 2], [1, 2]])
let C = A * B
// 利用逆矩阵求解
// ⎛ 1 1 ⎞ ⎛ 3 ⎞ ⎛ 2 ⎞
// ⎢ ⎟ * CC = ⎢ ⎟ CC = ⎢ ⎟
// ⎝ 1 -1 ⎠ ⎝ 1 ⎠ ⎝ 1 ⎠
let AA = Matrix([[1, 1], [1, -1]])
let BB = Matrix([[3], [1]])
let CC = inv(AA) * BB

应用的加速库函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
import Accelerate
public func sum(x: [Double]) -> Double {
var result: Double = 0.0
vDSP_sveD(x, 1, &result, vDSP_Length(x.count))
return result
}
public func max(x: [Double]) -> Double {
var result: Double = 0.0
vDSP_maxvD(x, 1, &result, vDSP_Length(x.count))
return result
}
public func mean(x: [Double]) -> Double {
var result: Double = 0.0
vDSP_meanvD(x, 1, &result, vDSP_Length(x.count))
return result
}
public func add(x: [Double], y: [Double]) -> [Double] {
var results = [Double](y)
cblas_daxpy(Int32(x.count), 1.0, x, 1, &results, 1)
return results
}
public func fft(input: [Double]) -> [Double] {
var real = [Double](input)
var imaginary = [Double](count: input.count, repeatedValue: 0.0)
var splitComplex = DSPDoubleSplitComplex(realp: &real, imagp: &imaginary)
let length = vDSP_Length(floor(log2(Float(input.count))))
let radix = FFTRadix(kFFTRadix2)
let weights = vDSP_create_fftsetupD(length, radix)
vDSP_fft_zipD(weights, &splitComplex, 1, length, FFTDirection(FFT_FORWARD))
var magnitudes = [Double](count: input.count, repeatedValue: 0.0)
vDSP_zvmagsD(&splitComplex, 1, &magnitudes, 1, vDSP_Length(input.count))
var normalizedMagnitudes = [Double](count: input.count, repeatedValue: 0.0)
vDSP_vsmulD(sqrt(magnitudes), 1, [2.0 / Double(input.count)], &normalizedMagnitudes, 1, vDSP_Length(input.count))
vDSP_destroy_fftsetupD(weights)
return normalizedMagnitudes
}