Swift: número aleatorio para integers de 64 bits?

Entonces, con mi proyecto actual, necesito trabajar con integers de 64 bits y necesito tomar numbers aleatorios entre ranges de hasta 100 mil millones. arc4random () / arc4random_uniform () solo funciona con integers sin signo de 32 bits.

Probablemente pueda cambiarlo un poco porque mi range mínimo / máximo para cada llamada probablemente no excederá los 2 mil millones, pero me gustaría contrastar mi futuro en caso de que decida que, bueno, necesito un range más amplio.

¿Algún consejo?

Con arc4random_buf() puedes crear numbers aleatorios "arbitrariamente grandes", por lo que esta sería una posible solución:

 // Swift 2: func random64(upper_bound: UInt64) -> UInt64 { // Generate 64-bit random number: var rnd : UInt64 = 0 arc4random_buf(&rnd, sizeofValue(rnd)) return rnd % upper_bound } // Swift 3: func random64(upper_bound: UInt64) -> UInt64 { // Generate 64-bit random number: var rnd : UInt64 = 0 arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd)) return rnd % upper_bound } 

Este método sufre el problema del "sesgo de module" cuando el límite superior no es una potencia de 2 (Ver ¿Por qué la gente dice que hay un sesgo de module cuando se usa un generador de numbers aleatorios? ). Aquí he traducido la respuesta https://stackoverflow.com/a/10989061/1187415 desde el hilo superior a Swift:

 // Swift 2: func random64(upper_bound: UInt64) -> UInt64 { // Generate 64-bit random value in a range that is // divisible by upper_bound: let range = UInt64.max - UInt64.max % upper_bound var rnd : UInt64 = 0 repeat { arc4random_buf(&rnd, sizeofValue(rnd)) } while rnd >= range return rnd % upper_bound } // Swift 3: func random64(upper_bound: UInt64) -> UInt64 { // Generate 64-bit random value in a range that is // divisible by upper_bound: let range = UInt64.max - UInt64.max % upper_bound var rnd : UInt64 = 0 repeat { arc4random_buf(&rnd, MemoryLayout.size(ofValue: rnd)) } while rnd >= range return rnd % upper_bound } 

(A primera vista, parece que el bucle podría no terminar, pero se puede demostrar que, en promedio, se necesitan less de 2 iteraciones).

Tal vez pueda componerlo a integers de 32 bits:

 var random64 = Int64(arc4random()) + (Int64(arc4random()) << 32) 

¡Aquí hay una solución aseada! (Me parece bien de todos modos, ya que acabo de deviselo)

 let hex = UUID().uuidString.components(separatedBy: "-").suffix(2).joined() let rand = UInt64(hex, radix: 0x10) 

Prueba rápida con Swift REPL:

https://repl.it/GeIs/0

 for _ in 0..<5_000_000 { let hex = UUID().uuidString.components(separatedBy: "-").suffix(2).joined() set.insert(UInt64(hex, radix: 0x10)!) } set.count // prints 5_000_000 

Como una extensión …

 import Foundation extension UInt64 { static var random: UInt64 { let hex = UUID().uuidString .components(separatedBy: "-") .suffix(2) .joined() return UInt64(hex, radix: 0x10)! } } 

Aquí hay algunos ayudantes que generalmente incluyo en mis proyectos. Tenga en count el ayudante limitado UInt64, funciona en gran medida de la misma manera que la respuesta de Martin R, excepto por las comprobaciones del caso frecuente de que el range es menor que UInt32.max y solo realiza una llamada a arc4random ().

 extension UInt32 { /// Returns a random number in `0...UInt32.max` static func random() -> UInt32 { return arc4random() } /// Returns a random number in `0..<upperBound` static func random(_ upperBound: UInt32) -> UInt32 { return arc4random_uniform(upperBound) } } extension UInt64 { private static func randomLowerHalf() -> UInt64 { return UInt64(UInt32.random()) } private static func randomLowerHalf(_ upperBound: UInt32) -> UInt64 { return UInt64(UInt32.random(upperBound)) } static func random() -> UInt64 { return (randomLowerHalf() << 32) &+ randomLowerHalf() } static func random(_ upperBound: UInt64) -> UInt64 { if let upperBound = UInt32(exactly: upperBound) { return randomLowerHalf(upperBound) } else if UInt64(UInt32.max) == upperBound { return randomLowerHalf() } else { var result: UInt64 repeat { result = random() } while result >= upperBound return result } } } extension Int32 { static func random() -> Int32 { return Int32(bitPattern: UInt32.random()) } static func random(_ upperBound: Int32) -> Int32 { assert(0 < upperBound, "upperBound(\(upperBound)) must be greater than 0") return Int32(bitPattern: UInt32.random(UInt32(bitPattern: upperBound))) } } extension Int64 { static func random() -> Int64 { return Int64(bitPattern: UInt64.random()) } static func random(_ upperBound: Int64) -> Int64 { assert(0 < upperBound, "upperBound(\(upperBound)) must be greater than 0") return Int64(bitPattern: UInt64.random(UInt64(bitPattern: upperBound))) } } extension Int { static func random() -> Int { return Int(IntMax.random()) } static func random(_ upperBound: Int) -> Int { assert(0 < upperBound, "upperBound(\(upperBound)) must be greater than 0") return Int(IntMax.random(IntMax(upperBound))) } }