swift 如何将两个数组元素相乘

s1ag04yj  于 2023-03-17  发布在  Swift
关注(0)|答案(5)|浏览(158)

我需要将一个数组乘以另一个数组的元素,就像数学中向量的阿达玛乘积一样。

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

我甚至弄不清楚代码,我试着一个元素一个元素地做,但这对我来说似乎太混乱了,有什么想法吗?

gmol1639

gmol16391#

“压缩”这两个数组给出元组序列(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,而不是闭包表达式:

let C = zip(A, B).map(*)
smdncfj3

smdncfj32#

单指令多数据

如果您的向量正好有4个分量,您可以使用iOS提供的超快simd(* 单指令多数据 *)指令。
它使用CPU来执行并行计算。
给定Int32的4个分量的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模块提供。

7y4bm7vi

7y4bm7vi3#

加速框架
对于向量乘法的主题,另一种替代方法(除了the neat simd covered by @appzYourLife's answer之外)是使用Accelerate framework。在这种情况下,具体来说就是vDSP methodsvDSP_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之前正确分配结果向量。

zaq34kh6

zaq34kh64#

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

使用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)

使用符合NumericExpressibleByArrayLiteral协议的自定义类型

您可以生成自己的符合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.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)
pcww981p

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])
 }

相关问题