我需要将数组乘以另一个数组,就像数学中的向量一样。
例如:A = [1,2,3,4]
B = [2,3,4,5]
C = A*B = [2,6,12,20]
我甚至无法弄清楚代码,我已经尝试逐个元素,但这对我来说似乎是一个解决方案,任何想法? (我是swift的初学者)
“压缩”两个数组给出了一系列元组(a_i, b_i)
,然后可以按元素相乘:
let A = [1,2,3,4]
let B = [2,3,4,5]
let C = zip(A, B).map { $0 * $1 }
print(C) // [2, 6, 12, 20]
(如果数组的长度不同,那么zip
会默默地忽略较长数组的额外元素。)
正如@appzYourLife正确地说的那样,你也可以直接将乘法运算符作为参数传递给map
而不是闭包表达式:
let C = zip(A, B).map(*)
如果你的向量有4个组件,你可以使用iOS提供的超高速simd
(单指令多数据)指令。
它使用CPU执行并行计算。
给出2个Int32
组分的2个向量
import simd
let a = int4(1, 2, 3, 4)
let b = int4(2, 3, 4, 5)
你可以乘以每个组件
let res = a &* b // int4(2, 6, 12, 20)
正如Martin R所指出的那样,
float(s)
模块也提供了double(s)
或simd
阵列。
对于矢量乘法的主题,另一个替代方案(除了the neat simd
covered by @appzYourLife's answer)正在使用Accelerate framework。在这种情况下,特别是vDSP methods vDSP_vmul
和vDSP_vmuld
,
func vDSP_vmul(UnsafePointer<Float>, vDSP_Stride, UnsafePointer<Float>, vDSP_Stride, UnsafeMutablePointer<Float>, vDSP_Stride, vDSP_Length) func vDSP_vmulD(UnsafePointer<Double>, vDSP_Stride, UnsafePointer<Double>, vDSP_Stride, UnsafeMutablePointer<Double>, vDSP_Stride, vDSP_Length)
例如,后者用于Double
值的两个向量的逐元素乘法:
import Accelerate
let a = [1.5, 2.5, 16.5, 7.5, 3.0]
let b = [3.0, 4.5, 0.25, 3.5, 6.25]
var result = [Double](repeating: 0.0, count: a.count)
if a.count == b.count {
vDSP_vmulD(a, 1, b, 1, &result, 1, vDSP_Length(a.count))
print(result) // [4.5, 11.25, 4.125, 26.25, 18.75]
}
请注意,使用Accelerate不像其他方法那样友好且安全,因为vDSP_vmulD
的向量参数被捕获为不安全指针(UnsafePointer<Double>
),并且我们有责任确保输入向量具有相同的长度,以及因为结果向量在vDSP_vmulD
的向量乘法之前被正确分配。
使用Swift 5,您可以使用以下方法之一来解决您的问题。
以下Playground示例代码显示了使用SIMD4
的元素乘法:
let vector1 = SIMD4(1, 2, 3, 4)
let vector2 = SIMD4(2, 3, 4, 5)
let vector3 = vector1 &* vector2
print(vector3) // prints: SIMD4<Int>(2, 6, 12, 20)
请注意,SIMD
协议符合ExpressibleByArrayLiteral
。因此,您可以使用数组文字初始化矢量:
var vector1: SIMD4 = [1, 2, 3, 4]
let vector2: SIMD4 = [2, 3, 4, 5]
vector1 &*= vector2
print(vector1) // prints: SIMD4<Int>(2, 6, 12, 20)
Numeric
and ExpressibleByArrayLiteral
protocols您可以构建符合Numeric
和ExpressibleByArrayLiteral
的自定义类型。以下Playground示例代码显示了如何实现和使用它:
struct Vector {
let x, y: Int
init(_ x: Int, _ y: Int) {
self.x = x
self.y = y
}
}
extension Vector: AdditiveArithmetic {
static var zero: Vector {
return Vector(0, 0)
}
static func +(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x + rhs.x, lhs.y + rhs.y)
}
static func +=(lhs: inout Vector, rhs: Vector) {
lhs = lhs + rhs
}
static func -(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x - rhs.x, lhs.y - rhs.y)
}
static func -=(lhs: inout Vector, rhs: Vector) {
lhs = lhs - rhs
}
}
extension Vector: ExpressibleByIntegerLiteral {
init(integerLiteral value: Int) {
x = value
y = value
}
}
import Darwin
extension Vector: Numeric {
var magnitude: Int {
// Implement according to your needs
return Int(Darwin.sqrt(Double(x * x + y * y)))
}
init?<T>(exactly source: T) where T : BinaryInteger {
guard let source = source as? Int else {
return nil
}
x = source
y = source
}
static func *(lhs: Vector, rhs: Vector) -> Vector {
return Vector(lhs.x * rhs.y, lhs.y * rhs.x)
}
static func *=(lhs: inout Vector, rhs: Vector) {
lhs = lhs * rhs
}
}
extension Vector: ExpressibleByArrayLiteral {
init(arrayLiteral elements: Int...) {
assert(elements.count == 2, "arrayLiteral should have exactly 2 elements")
self.x = elements[0]
self.y = elements[1]
}
}
用法:
let vector1 = Vector(1, 2)
let vector2 = Vector(2, 3)
let vector3 = vector1 * vector2
print(vector3) // prints: Vector(x: 3, y: 4)
let vector1: Vector = [1, 2]
let vector2: Vector = [2, 3]
let vector3 = vector1 * vector2
print(vector3) // prints: Vector(x: 3, y: 4)
let A = [1,2,3,4]
let B = [2,3,4,5]
var C = [Int]()
A.enumerated().forEach{ index, value in
return C.append(value * B[index])
}