2016-07-08 1 views
2

수백만 개의 계산을 수행해야하는 매우 큰 배열이 있습니다. Objective-C에서 배열은 NSData로 저장 될 것이고 나는 (합계, 더하기 등)에 Accelerate 함수를 사용하기 위해 C 배열로 추상화 할 것입니다. 그러나 (모든 곳에서 포인터를 사용하는 것과 관련된 명백한 문제가 있음) 스위프트 배열이 내장되어 있는지 확인하는 경계를 더 많이 사용하고 싶습니다. 따라서 두 배열을 사용하기 위해 중첩 된 withUnsafeBufferPointer를 사용할 수 있습니다.Accelerate 기능으로 ArraySlice를 사용하는 더 나은 방법은 무엇입니까?

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)") 

첫째, 컴파일러는 이미 캐스팅하는 방법을 알고 때 의도 한 형식이 이상한 것 같이 참 -_-에게 포인터를 갖는 [더블] 자체 (블록 내부에 전달 된 포인터 VDSP 기능 반면, 유형 UnsafeBufferPointer<Double>의입니다 UnsafePointer<Double>이 필요합니다 (배열 변수 자체를 전달하면 불만 없습니다). 둘째, 사용법을 이해하고 있지만 withUnsafeBufferPointer을 중첩해야한다는 것이 이상하게 보입니다. 마지막으로, ArraySlice<Double>을 입력 매개 변수 유형으로 사용하면 Double 배열과 해당 배열의 조각 모두에 함수를 일반화 할 수 없습니다.

더 좋은 방법이 있나요?

답변

3
  1. 실제로 재 작성은 완전히 새로운 배열을 만듭니다. 당신이

  2. 중첩 withUnsafeBufferPointer

  3. 은 참으로 정확하고 (내 지식) 피할 수없는 UnsafeBufferbaseAddress 속성을 사용 (그리고 스위프트 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)") 
    

    가 강제 풀다가 잘 될 것입니다 :

  4. 당신은 모두 모두 그

위한 프로토콜을 만들 수 있습니다, 여기에 이러한 변화와 코드 절대 널 포인터를주지 않을거야.

+0

나는 프로토콜을 생각해 봤어야했다. (나는 계속 제네릭을 사용하는 다른 방법을 시도했다.) 내가 혼란스러워하는 한 가지는 프로토콜이'count'를 가져야 만하는 이유입니다 (결과 배열은'x.count'가 유효하지 않다고 불평하기 때문에 결과 배열을 선언 할 수 없습니다). 'baseAddress'를 가지고 있습니다. 설명해 주시겠습니까? –

+0

@AdamJones 그것은'withUnsafeBufferPointer'의'x' 변수가 그 바깥 쪽의'x'와 같지 않기 때문에 그림자가 생깁니다. 'x'를 클릭하면 그것을 볼 수 있습니다. 'x' 대신에'xBuf'를 선택할 수 있습니다.''BaseAddress'' 속성을 가진'UnsafeBufferPointer'입니다. – Kametrixom

+0

Gotcha. 고마워요. –

관련 문제