如何用Apple的Swift语言生成一个随机数字?
我意识到Swift书提供了一个随机数生成器的实现。 在自己的程序中复制和粘贴这个实现是否是最佳实践? 还是有一个图书馆这样做,我们现在可以使用?
像在Objective-C中一样,使用标准库函数获得高质量的随机数: arc4random()
或arc4random_uniform()
。
它们在Darwin
模块中,所以如果你没有导入AppKit
, UIKit
或者Foundation
(为你导入),你需要import Darwin
。
对于0到n-1之间的随机整数,使用arc4random_uniform(n)
let diceRoll = Int(arc4random_uniform(6))
将结果转换为Int,以便您不必将显式types的值作为UInt32(它看起来不是Swifty)
编辑: 更新为Swift 3.0
arc4random
在Swift中运行良好,但基本函数仅限于32位整数types( Int
是iPhone 5S和现代Mac上的64位)。 这是一个generics函数,可以用整数文字表示一个types的随机数:
public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T { var r: T = 0 arc4random_buf(&r, MemoryLayout<T>.size) return r }
我们可以使用这个新的generics函数来扩展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 k: Int = random() % 10;
该方法将在给定的最小值和最大值之间生成一个随机的Int
值
func randomInt(min: Int, max:Int) -> Int { return min + Int(arc4random_uniform(UInt32(max - min + 1))) }
从iOS 9开始,您可以使用新的GameplayKit类以各种方式生成随机数。
你有四种源types可供select:一般的随机源(未命名,直到系统select它做什么),线性同余,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之类的东西来塑造随机分布。 这需要多一点解释,但如果你有兴趣,你可以阅读我的教程GameplayKit随机数字 。
你可以像你在C中那样做
let randomNumber = arc4random()
randomNumber
被推断为types为UInt32
(一个32位无符号整数)
使用arc4random_uniform()
用法:
arc4random_uniform(someNumber: UInt32) -> UInt32
这给你在0
到someNumber - 1
范围内的随机整数。
UInt32
的最大值是4,294,967,295(即2^32 - 1
)。
例子:
-
硬币翻转
let flip = arc4random_uniform(2) // 0 or 1
-
骰子滚动
let roll = arc4random_uniform(6) + 1 // 1...6
-
十月随机的一天
let day = arc4random_uniform(31) + 1 // 1...31
-
1990年的随机年份
let year = 1990 + arc4random_uniform(10)
一般forms:
let number = min + arc4random_uniform(max - min + 1)
其中number
, max
和min
是UInt32
。
关于什么…
arc4random()
你也可以通过使用arc4random()
来获得一个随机数,该数生成一个介于0和2 ^ 32-1之间的UInt32
。 因此,要得到一个0
到x-1
之间的随机数,可以用x
除以余数。 换句话说,使用剩余操作符(%) :
let number = arc4random() % 5 // 0...4
但是,这会产生轻微的模偏移 (请参阅这里和这里 ),所以推荐使用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
。 将此与UInt32
范围0...4,294,967,295
。 UInt32
的U
表示未签名 。
考虑以下错误:
UInt32(-1) // negative numbers cause integer overflow error UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error
所以你只需要确保你的input参数在UInt32
范围内,并且你不需要超出该范围的输出。
我已经能够使用rand()
来获得一个随机的CInt。 你可以通过使用这样的东西使它成为一个Int:
let myVar: Int = Int(rand())
你可以使用你最喜欢的C随机函数,只需要将值转换为Int。
10(0-9)之间的随机数的例子
import UIKit let randomNumber = Int(arc4random_uniform(10))
非常简单的代码 – 简单和短。
@ jstn的回答很好,但有点冗长。 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()
和所有其他的整数类都可以。
let MAX : UInt32 = 9 let MIN : UInt32 = 1 func randomNumber() { var random_number = Int(arc4random_uniform(MAX) + MIN) print ("random = ", random_number); }
这里是一个很好的工作的图书馆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 } }
var randomNumber = Int(arc4random_uniform(UInt32(**5**)))
这里5将确保随机数是从零到五生成的。 您可以相应地设置值。
我想补充一下现有的答案,Swift书中的随机数生成器例子是一个线性同余发生器(LCG),它是一个严格限制的例子,不应该是除了必须的小例子,其中随机性质量不会根本不重要。 LCG不应该用于密码学目的 。
arc4random()
更好,可以用于大多数目的,但不应该用于encryption的目的。
如果你想要保证密码安全的东西,使用SecCopyRandomBytes()
。 请注意,如果您将某个随机数生成器构build为某个东西,那么其他人可能会以密码为目的(例如密码,密钥或盐生成)而使用它,则无论如何您应该考虑使用SecCopyRandomBytes()
,即使您需求并不完全需要。
没有arc4Random_uniform()在一些版本的Xcode(在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) } } }
这些方法使用一个额外的随机数来确定要使用多lessUInt8
来创build随机数。 最后一行将[UInt8]
转换为UInt16
或UInt32
。
我不知道最后两个仍然算是真正的随机,但你可以调整它到你的喜好:)
你可以像这样使用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] } }