Int(UInt32) constructor goes awry

Starting with XCode 7 / Swift 2, I am seeing an intermittent EXC_ARM_BREAKPOINT, subcode=0xe7ffdefe crash in this code:

let rando = Int(arc4random())


Any ideas?


(Edited to remove the threadsafety question)

Answered by Jens in 8822022

You are essentially doing this (which will also overflow the signed int with the unsigned int value):

func foo() -> UInt32 {
   return UInt32(Int32.max) + 1
}
// foo will return a value that is 1 above what a signed 32 bit integer can hold (2147483647 + 1).
// So if you change " + 1" to " + 0", it will not crash.

let bar = Int32(foo()) // <-- Will crash the same way.
print(bar)


I guess you have to think about within what range you want your random values.


Since the function arc4random() returns an UInt32 within the closed range [0, UInt32.max], you'll have to turn those values into the type and range that you want.


For example if you would want a double value in the half open range [0.0, 1.0) you could do something like:

func rndDoubleHalfOpenZeroToOne() -> Double {
    return (Double(arc4random()) + 0.5) / (Double(UInt32.max) + 1.0)
}


And if what you want really is a random signed Int32 within the closed range [Int32.min, Int32.max], then I suppose you could do:

func rndInt32() -> Int32 {
    return Int32(bitPattern: arc4random())
}

Well, if arc4random() ever returns UInt32.max, that can't be converted to an Int on a 32 bit platform.

Accepted Answer

You are essentially doing this (which will also overflow the signed int with the unsigned int value):

func foo() -> UInt32 {
   return UInt32(Int32.max) + 1
}
// foo will return a value that is 1 above what a signed 32 bit integer can hold (2147483647 + 1).
// So if you change " + 1" to " + 0", it will not crash.

let bar = Int32(foo()) // <-- Will crash the same way.
print(bar)


I guess you have to think about within what range you want your random values.


Since the function arc4random() returns an UInt32 within the closed range [0, UInt32.max], you'll have to turn those values into the type and range that you want.


For example if you would want a double value in the half open range [0.0, 1.0) you could do something like:

func rndDoubleHalfOpenZeroToOne() -> Double {
    return (Double(arc4random()) + 0.5) / (Double(UInt32.max) + 1.0)
}


And if what you want really is a random signed Int32 within the closed range [Int32.min, Int32.max], then I suppose you could do:

func rndInt32() -> Int32 {
    return Int32(bitPattern: arc4random())
}
Int(UInt32) constructor goes awry
 
 
Q