我需要将一个数组乘以另一个数组的元素,就像数学中向量的阿达玛乘积一样。
A = [1,2,3,4] B = [2,3,4,5] C = A*B = [2,6,12,20]
我甚至弄不清楚代码,我试着一个元素一个元素地做,但这对我来说似乎太混乱了,有什么想法吗?
gmol16391#
“压缩”这两个数组给出元组序列(a_i, b_i),然后可以按元素相乘:
(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]
(If数组具有不同的长度,则zip默默地忽略较长数组的额外元素)。正如@appzYourLife正确指出的那样,您也可以将乘法运算符作为参数直接传递给map,而不是闭包表达式:
zip
map
let C = zip(A, B).map(*)
smdncfj32#
如果您的向量正好有4个分量,您可以使用iOS提供的超快simd(* 单指令多数据 *)指令。它使用CPU来执行并行计算。给定Int32的4个分量的2个向量
simd
Int32
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模块提供。
float(s)
double(s)
7y4bm7vi3#
加速框架对于向量乘法的主题,另一种替代方法(除了the neat simd covered by @appzYourLife's answer之外)是使用Accelerate framework。在这种情况下,具体来说就是vDSP methodsvDSP_vmul和vDSP_vmuld。
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值的两个向量的逐个元素乘法:
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之前正确分配结果向量。
vDSP_vmulD
UnsafePointer<Double>
zaq34kh64#
使用Swift 5,您可以使用以下方法之一来解决您的问题。
下面的Playground示例代码显示了使用SIMD4的元素级乘法:
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,因此,可以使用数组文本初始化向量:
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
您可以生成自己的符合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.x, lhs.y * rhs.y) } 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: 2, y: 6)
let vector1: Vector = [1, 2] let vector2: Vector = [2, 3] let vector3 = vector1 * vector2 print(vector3) // prints: Vector(x: 2, y: 6)
pcww981p5#
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]) }
5条答案
按热度按时间gmol16391#
“压缩”这两个数组给出元组序列
(a_i, b_i)
,然后可以按元素相乘:(If数组具有不同的长度,则
zip
默默地忽略较长数组的额外元素)。正如@appzYourLife正确指出的那样,您也可以将乘法运算符作为参数直接传递给
map
,而不是闭包表达式:smdncfj32#
单指令多数据
如果您的向量正好有4个分量,您可以使用iOS提供的超快
simd
(* 单指令多数据 *)指令。它使用CPU来执行并行计算。
给定
Int32
的4个分量的2个向量你可以将每个分量相乘
如 Martin R 所述,
float(s)
或double(s)
的阵列也由simd
模块提供。7y4bm7vi3#
加速框架
对于向量乘法的主题,另一种替代方法(除了the neat
simd
covered by @appzYourLife's answer之外)是使用Accelerate framework。在这种情况下,具体来说就是vDSP methodsvDSP_vmul
和vDSP_vmuld
。例如,后者用于
Double
值的两个向量的逐个元素乘法:请注意,使用Accelerate不像其他方法那样友好和安全,因为
vDSP_vmulD
的向量参数被捕获为不安全指针(UnsafePointer<Double>
),我们有责任确保输入向量具有相同的长度,以及在向量乘以vDSP_vmulD
之前正确分配结果向量。zaq34kh64#
使用Swift 5,您可以使用以下方法之一来解决您的问题。
使用SIMD vector types
下面的Playground示例代码显示了使用
SIMD4
的元素级乘法:请注意,
SIMD
协议符合ExpressibleByArrayLiteral
,因此,可以使用数组文本初始化向量:使用符合
Numeric
和ExpressibleByArrayLiteral
协议的自定义类型您可以生成自己的符合
Numeric
和ExpressibleByArrayLiteral
的自定义类型。下面的Playground示例代码演示如何实现和使用它:用法:
pcww981p5#