因此,在我目前的项目中,我需要使用64位整数,我需要在范围高达1000亿之间获取随机数。 arc4random()/ arc4random_uniform()仅适用于无符号32位整数。
我可能会稍微捏一下,因为我的每次通话的最小/最大范围可能不会超过20亿,但是如果我决定这样做,那么我希望将来自我保护,我确实需要更广泛的范围
有什么建议吗?
答案 0 :(得分:25)
更新:从 Swift 4.2 开始(随Xcode 10.1一起发布),Swift标准库中有一个统一的随机API,请参阅
您只需致电
即可UInt64.random(in: minValue ... maxValue)
获取给定范围内的随机数。
(Swift的前一个答案< 4.2:)使用arc4random_buf()
,你可以创建“任意大的”随机数,
所以这可能是一个解决方案:
// 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
}
当上限不是2的幂时,此方法会遇到“模偏差”问题(参见Why do people say there is modulo bias when using a random number generator?)。我在这里翻译了答案 https://stackoverflow.com/a/10989061/1187415从上面的帖子到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
}
(乍一看,它看起来好像循环可能没有终止,但它可以显示出来 平均需要少于2次迭代。)
答案 1 :(得分:17)
也许你可以把它组成32位整数:
var random64 = Int64(arc4random()) + (Int64(arc4random()) << 32)
答案 2 :(得分:2)
以下是我通常在项目中包含的一些助手。注意UInt64有界帮助器,它的工作方式与Martin R的答案大致相同,除了检查范围小于UInt32.max且只执行一次对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)))
}
}
答案 3 :(得分:2)
这是一个简洁的解决方案! (无论如何,因为我刚刚做完了)
let hex = UUID().uuidString.components(separatedBy: "-").suffix(2).joined()
let rand = UInt64(hex, radix: 0x10)
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
import Foundation
extension UInt64 {
static var random: UInt64 {
let hex = UUID().uuidString
.components(separatedBy: "-")
.suffix(2)
.joined()
return UInt64(hex, radix: 0x10)!
}
}