斯威夫特 4.2+
Xcode 10 附带的 Swift 4.2 为许多数据类型引入了新的易于使用的随机函数。您可以对数值类型调用 random()
方法。
let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
使用 arc4random_uniform(n)
表示 0 到 n-1 之间的随机整数。
let diceRoll = Int(arc4random_uniform(6) + 1)
将结果转换为 Int ,这样您就不必将您的变量显式键入为 UInt32
(这似乎不是 Swifty)。
0
。在您的代码中,diceRoll
可能是 0
。只是说...
Int(arc4random_uniform(6)+1)
。
arc3random_uniform(n)
的参数 n 转换为 UInt32(n)
。
arc4random
在 Swift 中运行良好,但基本函数仅限于 32 位整数类型(Int
在 iPhone 5S 和现代 Mac 上为 64 位)。这是一个可以用整数文字表示的类型的随机数的通用函数:
public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
var r: T = 0
arc4random_buf(&r, MemoryLayout<T>.size)
return r
}
我们可以使用这个新的通用函数来扩展 UInt64
,添加边界参数并减轻模偏差。 (这是直接从 arc4random.c 提升的)
public extension UInt64 {
public static func random(lower: UInt64 = min, upper: UInt64 = max) -> UInt64 {
var m: UInt64
let u = upper - lower
var r = arc4random(UInt64.self)
if u > UInt64(Int64.max) {
m = 1 + ~u
} else {
m = ((max - (u * 2)) + 1) % u
}
while r < m {
r = arc4random(UInt64.self)
}
return (r % u) + lower
}
}
有了它,我们可以为相同的参数扩展 Int64
,处理溢出:
public extension Int64 {
public static func random(lower: Int64 = min, upper: Int64 = max) -> Int64 {
let (s, overflow) = Int64.subtractWithOverflow(upper, lower)
let u = overflow ? UInt64.max - UInt64(~s) : UInt64(s)
let r = UInt64.random(upper: u)
if r > UInt64(Int64.max) {
return Int64(r - (UInt64(~lower) + 1))
} else {
return Int64(r) + lower
}
}
}
为了完成家庭...
private let _wordSize = __WORDSIZE
public extension UInt32 {
public static func random(lower: UInt32 = min, upper: UInt32 = max) -> UInt32 {
return arc4random_uniform(upper - lower) + lower
}
}
public extension Int32 {
public static func random(lower: Int32 = min, upper: Int32 = max) -> Int32 {
let r = arc4random_uniform(UInt32(Int64(upper) - Int64(lower)))
return Int32(Int64(r) + Int64(lower))
}
}
public extension UInt {
public static func random(lower: UInt = min, upper: UInt = max) -> UInt {
switch (_wordSize) {
case 32: return UInt(UInt32.random(UInt32(lower), upper: UInt32(upper)))
case 64: return UInt(UInt64.random(UInt64(lower), upper: UInt64(upper)))
default: return lower
}
}
}
public extension Int {
public static func random(lower: Int = min, upper: Int = max) -> Int {
switch (_wordSize) {
case 32: return Int(Int32.random(Int32(lower), upper: Int32(upper)))
case 64: return Int(Int64.random(Int64(lower), upper: Int64(upper)))
default: return lower
}
}
}
毕竟,我们终于可以做这样的事情了:
let diceRoll = UInt64.random(lower: 1, upper: 7)
var r = arc4random(UInt64)
。请指教你在这里的意思是什么?
UInt64
调用函数 arc4random
(在第一个代码块中定义)是一个 Type
。
arc4random_buf
。这些扩展的目的是完全按照 arc4random_uniform
所做的(减轻模偏差),除了 64 位类型。
为 Swift 4.2 编辑
从 Swift 4.2 开始,您现在可以使用 Swift 自己的原生函数,而不是使用导入的 C 函数 arc4random_uniform()。
// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)
您也可以使用 random(in:)
获取其他原始值的随机值;例如 Int、Double、Float 甚至 Bool。
斯威夫特版本 < 4.2
此方法将在给定的最小值和最大值之间生成一个随机 Int
值
func randomInt(min: Int, max: Int) -> Int {
return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
我使用了这段代码:
var k: Int = random() % 10;
random is unavailable in Swift: Use arc4random instead.
从 iOS 9 开始,您可以使用新的 GameplayKit 类以多种方式生成随机数。
您有四种源类型可供选择:一般随机源(未命名,由系统选择它的功能)、线性同余、ARC4 和 Mersenne Twister。这些可以生成随机整数、浮点数和布尔值。
在最简单的层面上,您可以从系统的内置随机源生成一个随机数,如下所示:
GKRandomSource.sharedRandom().nextInt()
这会生成一个介于 -2,147,483,648 和 2,147,483,647 之间的数字。如果你想要一个介于 0 和上限(不包括)之间的数字,你可以使用:
GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
GameplayKit 内置了一些方便的构造函数来处理骰子。例如,您可以像这样滚动一个六面骰子:
let d6 = GKRandomDistribution.d6()
d6.nextInt()
另外,您可以使用 GKShuffledDistribution 之类的东西来塑造随机分布。这需要更多解释,但如果您有兴趣,可以read my tutorial on GameplayKit random numbers。
import GameplayKit
。 Swift 3 将语法更改为 GKRandomSource.sharedRandom().nextInt(upperBound: 6)
你可以像在 C 中那样做:
let randomNumber = arc4random()
randomNumber
被推断为 UInt32
类型(32 位无符号整数)
rand
、arc4random
、drand48
和朋友都在 Darwin
模块中。如果您正在构建 Cocoa、UIKit 或 Foundation 应用程序,它已经为您导入,但您需要在 Playground 中import Darwin
。
使用 arc4random_uniform()
用法:
arc4random_uniform(someNumber: UInt32) -> UInt32
这会为您提供 0
到 someNumber - 1
范围内的随机整数。
UInt32
的最大值为 4,294,967,295(即 2^32 - 1
)。
例子:
硬币翻转 let flip = arc4random_uniform(2) // 0 或 1
掷骰子 let roll = arc4random_uniform(6) + 1 // 1...6
十月的随机日 let day = arc4random_uniform(31) + 1 // 1...31
1990 年代的随机年份让年份 = 1990 + arc4random_uniform(10)
一般形式:
let number = min + arc4random_uniform(max - min + 1)
其中 number
、max
和 min
是 UInt32
。
关于什么...
arc4random()
您还可以使用 arc4random()
获得一个随机数,它产生一个介于 0 和 2^32-1 之间的 UInt32
。因此,要获得 0
和 x-1
之间的随机数,您可以将其除以 x
并取余数。或者换句话说,使用 Remainder Operator (%):
let number = arc4random() % 5 // 0...4
但是,这会产生轻微的 modulo bias(另请参见 here 和 here),因此建议使用 arc4random_uniform()
。
与 Int
相互转换
通常,为了在 Int
和 UInt32
之间来回转换,可以执行以下操作:
let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))
但是,问题在于 Int
在 32 位系统上的范围为 -2,147,483,648...2,147,483,647
,而在 64 位系统上的范围为 -9,223,372,036,854,775,808...9,223,372,036,854,775,807
。将此与 0...4,294,967,295
的 UInt32
范围进行比较。 UInt32
的 U
表示 无符号。
考虑以下错误:
UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error
因此,您只需确保输入参数在 UInt32
范围内,并且您也不需要超出该范围的输出。
10 (0-9) 之间的随机数示例;
import UIKit
let randomNumber = Int(arc4random_uniform(10))
非常简单的代码 - 简单而简短。
我已经能够使用 rand()
来获得随机 CInt。您可以使用以下方法使其成为 Int :
let myVar: Int = Int(rand())
您可以使用您最喜欢的 C 随机函数,并在需要时将值转换为 Int。
random()
,它返回一个 Int
而不是 UInt32
- 就像@SomeGuy 提到的那样,只需在使用它之前在任何地方调用一次 srandom(arc4random())
,以确保每次执行它都有一个不同的随机种子你的程序。
@jstn's answer 很好,但有点冗长。 Swift 被称为面向协议的语言,因此我们可以通过添加协议扩展的默认实现来实现相同的结果,而无需为整数系列中的每个类实现样板代码。
public extension ExpressibleByIntegerLiteral {
public static func arc4random() -> Self {
var r: Self = 0
arc4random_buf(&r, MemoryLayout<Self>.size)
return r
}
}
现在我们可以这样做:
let i = Int.arc4random()
let j = UInt32.arc4random()
并且所有其他整数类都可以。
在 Swift 4.2 中,您可以通过对所需的任何数字类型调用 random()
方法来生成随机数,并提供您想要使用的范围。例如,这会生成 1 到 9 范围内的随机数,包括两边
let randInt = Int.random(in: 1..<10)
也与其他类型
let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
更新日期:2022 年 6 月 9 日。
斯威夫特 5.7
假设我们有一个数组:
let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
对于 iOS 和 macOS,您可以在 Xcode 的框架 GameKit
中使用系统范围的随机源。在这里您可以找到 GKRandomSource
类及其 sharedRandom()
类方法:
import GameKit
private func randomNumberGenerator() -> Int {
let rand = GKRandomSource.sharedRandom().nextInt(upperBound: numbers.count)
return numbers[rand]
}
randomNumberGenerator()
您还可以使用返回集合的随机元素的 randomElement()
方法:
let randomNumber = numbers.randomElement()!
print(randomNumber)
或使用 arc4random_uniform()
。注意此方法返回 UInt32
类型。
let generator = Int(arc4random_uniform(11))
print(generator)
当然,我们可以使用 makeIterator()
方法返回集合元素的迭代器。
let iterator: Int = (1...10).makeIterator().shuffled().first!
print(iterator)
您在此处看到的最后一个示例在 static func random(in range: ClosedRange<Int>) -> Int
的帮助下返回指定范围内的随机值。
let randomizer = Int.random(in: 1...10)
print(randomizer)
伪随机 Double 数字生成器 drand48()
返回一个介于 0.0 和 1.0 之间的值。
import Foundation
let randomInt = Int(drand48() * 10)
这是一个做得很好的图书馆https://github.com/thellimist/SwiftRandom
public extension Int {
/// SwiftRandom extension
public static func random(lower: Int = 0, _ upper: Int = 100) -> Int {
return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
}
}
public extension Double {
/// SwiftRandom extension
public static func random(lower: Double = 0, _ upper: Double = 100) -> Double {
return (Double(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
}
}
public extension Float {
/// SwiftRandom extension
public static func random(lower: Float = 0, _ upper: Float = 100) -> Float {
return (Float(arc4random()) / 0xFFFFFFFF) * (upper - lower) + lower
}
}
public extension CGFloat {
/// SwiftRandom extension
public static func random(lower: CGFloat = 0, _ upper: CGFloat = 1) -> CGFloat {
return CGFloat(Float(arc4random()) / Float(UINT32_MAX)) * (upper - lower) + lower
}
}
从 Swift 4.2 开始
有一组新的 API:
let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
所有数字类型现在都有接受范围的 random(in:) 方法。
它返回一个均匀分布在该范围内的数字。
TL;博士
那么,“好”的旧方法有什么问题?
您必须使用导入的 C API(它们在平台之间有所不同)。而且……
如果我告诉你随机不是那么随机怎么办?
如果您像 arc4random() % aNumber
一样使用 arc4random()
(计算余数),则结果不会均匀分布在 0
和 aNumber
之间。有一个称为模数偏差的问题。
模偏置
通常,该函数会在 0
和 MAX 之间生成一个随机数(取决于类型等)。举个简单的例子,假设最大数是 7
,并且您关心范围 0 ..< 2
(或区间 [0, 3),如果您愿意的话)中的随机数。
个别数字的概率是:
0:3/8 = 37.5%
1:3/8 = 37.5%
2:2/8 = 25%
换句话说,与 2 相比,您更有可能以 0 或 1 结束。当然,请记住,这是极其简化的,并且 MAX 数要高得多,使其更“公平”。
SE-0202 - Swift 4.2 中的随机统一解决了这个问题
let MAX : UInt32 = 9
let MIN : UInt32 = 1
func randomNumber()
{
var random_number = Int(arc4random_uniform(MAX) + MIN)
print ("random = ", random_number);
}
我想在现有答案中补充一点,Swift 书中的随机数生成器示例是线性同余生成器(LCG),它是一个严重受限的示例,除了必须琐碎的示例之外不应如此,其中随机性的质量不一点都不重要。 LCG 永远不应该用于加密目的。
arc4random()
要好得多,可用于大多数用途,但同样不应用于加密目的。
如果您想要保证加密安全的东西,请使用 SecCopyRandomBytes()
。请注意,如果您将随机数生成器构建到某个东西中,其他人可能最终会(错误)将它用于加密目的(例如密码、密钥或盐生成),那么您无论如何都应该考虑使用 SecCopyRandomBytes()
,即使您的需要并不完全需要。
斯威夫特 4.2
再见,导入 Foundation C 库 arc4random_uniform()
// 1
let digit = Int.random(in: 0..<10)
// 2
if let anotherDigit = (0..<10).randomElement() {
print(anotherDigit)
} else {
print("Empty range.")
}
// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
您使用 random(in:) 从范围中生成随机数字。如果范围为空,则 randomElement() 返回 nil,因此您解开返回的 Int?如果让。您使用 random(in:) 生成随机 Double、Float 或 CGFloat 并使用 random() 返回随机 Bool。
var randomNumber = Int(arc4random_uniform(UInt32(5)))
这里 5 将确保从零到四生成随机数。您可以相应地设置该值。
在某些版本的 Xcode 中没有 arc4Random_uniform() (在 7.1 中它运行但不会自动完成)。您可以改为这样做。
生成一个 0-5 的随机数。第一的
import GameplayKit
然后
let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
以下代码将生成 0 到 255 之间的安全随机数:
extension UInt8 {
public static var random: UInt8 {
var number: UInt8 = 0
_ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
return number
}
}
你这样称呼它:
print(UInt8.random)
对于更大的数字,它变得更加复杂。这是我能想到的最好的:
extension UInt16 {
public static var random: UInt16 {
let count = Int(UInt8.random % 2) + 1
var numbers = [UInt8](repeating: 0, count: 2)
_ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
return numbers.reversed().reduce(0) { $0 << 8 + UInt16($1) }
}
}
extension UInt32 {
public static var random: UInt32 {
let count = Int(UInt8.random % 4) + 1
var numbers = [UInt8](repeating: 0, count: 4)
_ = SecRandomCopyBytes(kSecRandomDefault, count, &numbers)
return numbers.reversed().reduce(0) { $0 << 8 + UInt32($1) }
}
}
这些方法使用一个额外的随机数来确定将使用多少个 UInt8
来创建随机数。最后一行将 [UInt8]
转换为 UInt16
或 UInt32
。
我不知道最后两个是否仍然算作真正随机的,但您可以根据自己的喜好对其进行调整:)
斯威夫特 4.2
Swift 4.2 在标准库中包含了一个原生且功能相当全面的随机数 API。 (Swift Evolution proposal SE-0202)
let intBetween0to9 = Int.random(in: 0...9)
let doubleBetween0to1 = Double.random(in: 0...1)
所有数字类型都有静态 random(in:),它接受范围并返回给定范围内的随机数
您可以像这样使用 GeneratorOf
:
var fibs = ArraySlice([1, 1])
var fibGenerator = GeneratorOf{
_ -> Int? in
fibs.append(fibs.reduce(0, combine:+))
return fibs.removeAtIndex(0)
}
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
println(fibGenerator.next())
我使用此代码生成一个随机数:
//
// FactModel.swift
// Collection
//
// Created by Ahmadreza Shamimi on 6/11/16.
// Copyright © 2016 Ahmadreza Shamimi. All rights reserved.
//
import GameKit
struct FactModel {
let fun = ["I love swift","My name is Ahmadreza","I love coding" ,"I love PHP","My name is ALireza","I love Coding too"]
func getRandomNumber() -> String {
let randomNumber = GKRandomSource.sharedRandom().nextIntWithUpperBound(fun.count)
return fun[randomNumber]
}
}
细节
xCode 9.1,斯威夫特 4
面向数学的解决方案 (1)
import Foundation
class Random {
subscript<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
get {
return rand(min-1, max+1)
}
}
}
let rand = Random()
func rand<T>(_ min: T, _ max: T) -> T where T : BinaryInteger {
let _min = min + 1
let difference = max - _min
return T(arc4random_uniform(UInt32(difference))) + _min
}
溶液的使用(一)
let x = rand(-5, 5) // x = [-4, -3, -2, -1, 0, 1, 2, 3, 4]
let x = rand[0, 10] // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
面向程序员的解决方案 (2)
不要忘记在此处添加面向数学的解决方案 (1) 代码
import Foundation
extension CountableRange where Bound : BinaryInteger {
var random: Bound {
return rand(lowerBound-1, upperBound)
}
}
extension CountableClosedRange where Bound : BinaryInteger {
var random: Bound {
return rand[lowerBound, upperBound]
}
}
溶液的使用(二)
let x = (-8..<2).random // x = [-8, -7, -6, -5, -4, -3, -2, -1, 0, 1]
let x = (0..<10).random // x = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
let x = (-10 ... -2).random // x = [-10, -9, -8, -7, -6, -5, -4, -3, -2]
完整样本
不要忘记在此处添加解决方案(1)和解决方案(2)代码
private func generateRandNums(closure:()->(Int)) {
var allNums = Set<Int>()
for _ in 0..<100 {
allNums.insert(closure())
}
print(allNums.sorted{ $0 < $1 })
}
generateRandNums {
(-8..<2).random
}
generateRandNums {
(0..<10).random
}
generateRandNums {
(-10 ... -2).random
}
generateRandNums {
rand(-5, 5)
}
generateRandNums {
rand[0, 10]
}
样本结果
https://i.stack.imgur.com/AlR58.png