[英]Swift: Random number for 64-bit integers?
因此,在我當前的項目中,我需要使用 64 位整數,並且需要在高達 1000 億的范圍內抓取隨機數。 arc4random()/arc4random_uniform() 僅適用於無符號 32 位整數。
我可能會稍微捏造一下,因為我每次調用的最小/最大范圍可能不會超過 20 億,但我想對自己進行未來驗證,以防我決定,好吧,我確實需要更廣泛的范圍。
有什么建議嗎?
更新:從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 的冪時,此方法會遇到“模偏差”問題(請參閱為什么人們說使用隨機數生成器時存在模偏差? )。 在這里,我已將答案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 次迭代。)
也許你可以用兩個 32 位整數組成它:
var random64 = Int64(arc4random()) + (Int64(arc4random()) << 32)
以下是我通常包含在我的項目中的一些助手。 請注意 UInt64 bounded helper,它的工作方式與 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)))
}
}
這是一個巧妙的解決方案! (反正我是這么想的,因為我剛剛編的)
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)!
}
}
您可以使用UInt64.random(in:)和UInt64.max API 生成隨機無符號 64 位數字:
UInt64.random(in: 0...UInt64.max)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.