Swift:如何将数组乘以数组(Math:vector by vector)SIMD矢量类型Numeric ExpressibleByArrayLiteral

问题描述 投票:10回答:5

我需要将数组乘以另一个数组,就像数学中的向量一样。

例如:A = [1,2,3,4] B = [2,3,4,5] C = A*B = [2,6,12,20]

我甚至无法弄清楚代码,我已经尝试逐个元素,但这对我来说似乎是一个解决方案,任何想法? (我是swift的初学者)

arrays swift vector multiplying
5个回答
19
投票

“压缩”两个数组给出了一系列元组(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(*)

6
投票

单指令多数据

如果你的向量有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阵列。


5
投票

加速框架

对于矢量乘法的主题,另一个替代方案(除了the neat simd covered by @appzYourLife's answer)正在使用Accelerate framework。在这种情况下,特别是vDSP methods vDSP_vmulvDSP_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的向量乘法之前被正确分配。


1
投票

使用Swift 5,您可以使用以下方法之一来解决您的问题。


#1. Using SIMD vector types

以下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)

#2. Using a custom type that conforms to Numeric and ExpressibleByArrayLiteral protocols

您可以构建符合NumericExpressibleByArrayLiteral的自定义类型。以下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)

0
投票
 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])
 }
© www.soinside.com 2019 - 2024. All rights reserved.