Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does the following code crash on an iPhone 5 but not an iPhone 5S?

Tags:

swift

func rand(max: Int?) -> Int {
    var index = Int(arc4random())
    return max? != nil ? (index % max!) : index
}

I get an exception on the last line: EXC_BAD_INSTRUCTION

I'm guessing it has something to do with the fact that the iPhone 5S is 64 bit while the 5 is not, but I don't see anything in the function above that deals with 64 bits?

Edit

I was able to resolve the issue with the following adjustments, but I still cannot explain why.

func rand(max: Int?) -> Int {
    var index = arc4random()
    return max? != nil ? Int(index % UInt32(max!)) : Int(index)
}
like image 356
Snowman Avatar asked Aug 12 '14 21:08

Snowman


2 Answers

The Int integer type is a 32-bit integer on the iPhone 5 and a 64-bit integer on the 5S. Since arc4random() returns a UInt32, which has twice the positive range of an Int on the iPhone 5, your first version basically has a 50% chance of crashing on this line:

var index = Int(arc4random())

Your modified version waits to convert until you take the modulo sum with max, so it's safe to convert to Int there. You should check out arc4random_uniform, which handles the modulo for you and avoids some bias inherent in your current implementation.

like image 175
Nate Cook Avatar answered Oct 31 '22 12:10

Nate Cook


As it seems like you found out, arc4random returns an unsigned 32 bit integer. So 0 to 4,294,967,295. Also, Int is a different size depending on the system that it is running on.

From "Swift reference:"

On a 32-bit platform, Int is the same size as Int32.
On a 64-bit platform, Int is the same size as Int64.

On an iPhone 5, Int will only hold −2,147,483,648 to +2,147,483,647. On an iPhone 5S, Int can hold −9,223,372,036,854,775,808 to +9,223,372,036,854,775,807. An unsigned 32 bit integer can overflow a Int32 but never a Int64.

More information on what random function to use and why.

like image 31
sanz Avatar answered Oct 31 '22 11:10

sanz