2

何百万もの計算を実行する必要がある非常に大きな配列がいくつかあります。Objective-C では、配列は NSData として格納され、それらを C 配列に抽象化して、Accelerate 関数 (sum、add など) を使用します。ただし、(どこでもポインターを使用することに関する明らかな問題を考えると) Swift 配列に組み込まれている境界チェックをもっと活用したいと思います。したがって、ネストされた withUnsafeBufferPointer を使用して、2 つの配列を操作できます。

func mult(_ x: ArraySlice<Double>, _ y: ArraySlice<Double>) -> [Double] {
    assert(x.count == y.count)

    var results = [Double](repeating:0, count: x.count)

    x.withUnsafeBufferPointer({xBuffer in
        y.withUnsafeBufferPointer({yBuffer in
            vDSP_vmulD([Double](xBuffer), 1, [Double](yBuffer), 1, &results, 1, vDSP_Length(xBuffer.count))
        })
    })

    return results
}

var testArray = [Double]([0,1,2,3,4,5,6,7,8,9,10])
var testArray2 = [Double]([2,2,2,2,2,2,2,2,2,2,2])

let results = mult(testArray[5...10], testArray2[5...10])
print("\(results)")

まず、コンパイラが [Double] 自体をキャストする方法を既に知っている場合、意図した型としてポインターを再キャストすることは奇妙に思えます (ブロック内で渡されるポインターの型は ですUnsafeBufferPointer<Double>が、vDSP 関数は期待されますUnsafePointer<Double>(ここでも、配列変数自体を渡した場合の苦情))。withUnsafeBufferPointer第二に、使用法は理解していますが、見栄えをネストする必要があります。最後にArraySlice<Double>、入力パラメーターの型として使用すると、関数を Double 配列とその配列のスライスの両方に一般化できません。

これを行うより良い方法はありますか?

4

1 に答える 1

3
  1. 再キャストは確かに問題です。まったく新しい配列が作成されます。それを避けるために、のbaseAddressプロパティを使用できますUnsafeBuffer(Swift 3でアンラップします)

  2. ネストされたwithUnsafeBufferPointerものは確かに正しく、避けることはできません (私の知る限り)。バッファ ポインタは、クロージャ内でのみ有効です。

  3. そのためのプロトコルを作成できます

全体として、これらの変更を加えたコードは次のとおりです。

import Accelerate

protocol ArrayType {
    associatedtype Element
    var count : Int { get }
    func withUnsafeBufferPointer<R>(_ body: @noescape (UnsafeBufferPointer<Element>) throws -> R) rethrows -> R
}

extension Array : ArrayType {}
extension ArraySlice : ArrayType {}
extension ContiguousArray : ArrayType {}

func mult<A : ArrayType where A.Element == Double>(x: A, y: A) -> [Double] {
    assert(x.count == y.count)

    var result = [Double](repeating: 0, count: x.count)

    x.withUnsafeBufferPointer { x in
        y.withUnsafeBufferPointer { y in
            vDSP_vmulD(x.baseAddress!, 1, y.baseAddress!, 1, &result, 1, vDSP_Length(x.count))
        }
    }

    return result
}

var testArray1 : [Double] = [0,1,2,3,4,5,6,7,8,9,10]
var testArray2 : [Double] = [2,2,2,2,2,2,2,2,2,2,2]

let results = mult(x: testArray1[5...10], y: testArray2[5...10])
print("\(results)")

強制アンラップは問題ありません。これは、3 つの適合型が null ポインターを提供しないためです。

于 2016-07-08T04:08:37.690 に答える