heisenberg
heisenberg

Reputation: 7

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.

Upvotes: 0

Views: 905

Answers (1)

matthew.healy
matthew.healy

Reputation: 365

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:

  • You might noticed I swapped the var in the code sample above for a let. Since value is never mutated (instead being redefined at each pass through the loop) it doesn't need to be mutable. Removing mutable state will make it easier to find problems in your code.
  • You've used a lot of while loops with mutable state to track progress through them. These can all be replaced with for...in loops. E.g. the first while can be replaced with for i in 0..<steps without any affecting the code. This again helps cut down on mutable state, and programmer error.

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)

Upvotes: 0

Related Questions