arraysswiftloopsswift2exc-bad-instruction

Swift: Execution was interrupted, reason: EXC_BAD_INSTRUCTION error


When I attempt this in Playground:

func StockEvolution(S_0:Double, _ down:Double, _ up:Double, _ totalsteps:Int, _ upsteps:Int) -> Double // function being used in calcCall()
{
    var S_t:Double = S_0 * pow(up, Double(upsteps)) * pow(down, Double(totalsteps - upsteps))
    return S_t 
}

func CallPayoff(S:Double, _ K:Double) -> Double // function being used in calcCall()
{
    return max(S - K, 0.0)
}

func calcCall(S_0:Double, _ down:Double, _ up:Double, _ r:Double, _ steps:Int, _ K:Double) -> Double //calculate Call-Option
{
    var prices = [Double]()
    var q = 0.6 //risk-neutral probability factor

var i = 0
while i < steps
{
    var payOff = CallPayoff(StockEvolution(S_0, down, up, steps, i), K)
    prices.append(payOff)
    i += 1
}

var n = steps - 1
while n >= 0
{
    var j = 0
    while j <= n
    {
        var value = (1 / r) * (prices[j + 1] * q + (1 - q) * prices[j])
        prices.removeAtIndex(j)
        prices.insert(value, atIndex: j)
        j += 1
    }
    n -= 1
}
return prices[0]
}

By doing this:

var checkPrice = calcCall(100, 0.6, 1.5, 1.05, 10, 200)

It gives me this error:

Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)

I can't seem to find the bug in my code. I've tried with different input values but the error still occurs.

It would be great if you could have a look at my code and help me to fix this issue. Thanks for your efforts.


Solution

  • The issue is with your nested while loops. The first time you loop through, n is set to 9, which means that on the final pass through the nested loop you end up with j == 9, which clearly means j + 1 == 10. But you're trying to get prices[j + 1] == prices[10], which doesn't exist. Hence the crash.

    To see this, add the following if statement:

    if j + 1 < prices.count {
        let value = (1 / r) * (prices[j + 1] * q + (1 - q) * prices[j])
        prices.removeAtIndex(j)
        prices.insert(value, atIndex: j)
    }
    j += 1
    

    You'll no longer get the bad access error.

    Now, I don't know the problem domain at all, so I can't say why your algorithm was incorrect. As such the answer I've provided may not give you the values you expect. You'll probably have to work out why you're trying to access a non-existent index, and how to work around that.

    Finally, if I may, some general style points:

    I took the liberty of rewriting your code to make it a bit more "Swifty", while also removing as much mutable state as possible. Here it is:

    func stockEvolution(s_0: Double, _ down: Double, _ up: Double, _ totalsteps: Int, _ upsteps: Int) -> Double {
        let s_t: Double = s_0 * pow(up,  Double(upsteps)) * pow(down,  Double(totalsteps - upsteps))
        return s_t
    }
    
    func callPayoff(s: Double, _ k: Double) -> Double {
        return max(s - k, 0.0)
    }
    
    func calcCall(s_0: Double, _ down: Double, _ up: Double, _ r: Double, _ steps:Int, _ k: Double) -> Double {
        var prices = Array(0..<steps).map { step in
            return callPayoff(stockEvolution(s_0, down, up, steps, step), k)
        }
        let q = 0.6 //risk-neutral probability factor
    
        for n in (0..<steps).reverse() {
            for j in 0...n where j + 1 < prices.count {
                let value = (1 / r) * (prices[j + 1] * q + (1 - q) * prices[j])
                prices.removeAtIndex(j)
                prices.insert(value, atIndex: j)
            }
        }
        return prices[0]
    }
    
    let checkPrice = calcCall(100, 0.6, 1.5, 1.05, 10, 200)