Search code examples
swiftunsafe-pointersvdspunsafemutablepointeraccelerate

Why doesn't vDSP_maxv find the max value in the vector?


vDSP_maxv is not assigning the max value to output in the code below.

I expected the last line to print 2, but instead it prints something different each time, usually a very large or small number like 2.8026e-45

I've read this tutorial, the documentation, and the inline documentation in the header file for vDSP_maxv, but I don't see why the code below isn't producing the expected result.

Making numbers an UnsafePointer instead of an UnsafeMutablePointer didn't work, nor did a number of other things I've tried, so maybe I'm missing something fundamental.

import Accelerate

do {
    // INPUT - pointer pointing at: 0.0, 1.0, 2.0
    let count = 3
    let numbers = UnsafeMutablePointer<Float>
        .allocate(capacity: count)
    defer { numbers.deinitialize() }
    for i in 0..<count {
        (numbers+i).initialize(to: Float(i))
    }

    // OUTPUT
    var output = UnsafeMutablePointer<Float>
        .allocate(capacity: 1)

    // FIND MAX
    vDSP_maxv(
        numbers,
        MemoryLayout<Float>.stride,
        output,
        vDSP_Length(count)
    )
    print(output.pointee) // prints various numbers, none of which are expected
}

Solution

  • You are mistaking the usage of the stride parameter to vDSP_maxv. You need to pass the number of elements consisting a single stride, not the number of bytes.

    vDSP_maxv(::::)

    *C = -INFINITY;
    for (n = 0; n < N; ++n)
        if (*C < A[n*I])
            *C = A[n*I];
    

    In the pseudo code above, I represents the stride parameter, and you see giving 4 (MemoryLayout<Float>.stride) to I would generate indexes exceeding the bound of A (your numbers).

    Some other parts fixed to fit my preference, but the most important thing is the second parameter for vDSP_maxv:

    import Accelerate
    
    do {
        // INPUT - pointer pointing at: 0.0, 1.0, 2.0
        let numbers: [Float] = [0.0, 1.0, 2.0]
    
        // OUTPUT
        var output: Float = Float.nan
    
        // FIND MAX
        vDSP_maxv(
            numbers,
            1, //<- when you want to use all elements in `numbers` continuously, you need to pass `1`
            &output,
            vDSP_Length(numbers.count)
        )
        print(output) //-> 2.0
    }