Skip to content

Instantly share code, notes, and snippets.

@superlopuh
Created September 15, 2017 09:07
Show Gist options
  • Save superlopuh/e706ccd97e103a1b4abd5bfdfb7b58eb to your computer and use it in GitHub Desktop.
Save superlopuh/e706ccd97e103a1b4abd5bfdfb7b58eb to your computer and use it in GitHub Desktop.
Random Number Generation in Swift
import Darwin
// MARK: Integers
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)))
}
}
// MARK: Collections
extension RandomAccessCollection where IndexDistance == Int {
public func randomElement() -> Generator.Element? {
guard !isEmpty else { return nil }
return self[index(startIndex, offsetBy: Int.random(count))]
}
}
extension MutableCollection where Self: RandomAccessCollection, IndexDistance == Int, Indices.SubSequence: Sequence, Indices.SubSequence.Iterator.Element == Index {
public func shuffled() -> Self {
var copy = self
copy.shuffleInPlace()
return copy
}
public mutating func shuffleInPlace() {
guard 1 < count else { return }
for i in indices.dropLast() {
let j = self.index(i, offsetBy: Int.random(distance(from: i, to: endIndex)))
guard i != j else { continue }
swap(&self[i], &self[j])
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment