如何在Apple的Swift语言中生成一个随机数?

doo*_*ree 423 random swift

我意识到Swift书提供了随机数生成器的实现.最好的做法是将此实现复制并粘贴到自己的程序中吗?或者是否有一个我们现在可以使用的库?

Joh*_*ley 495

使用arc4random_uniform(n)为0和n-1之间的随机整数.

let diceRoll = Int(arc4random_uniform(6) + 1)
Run Code Online (Sandbox Code Playgroud)

将结果转换为Int,这样您就不必明确键入您的变量UInt32(这似乎是非Swifty).

  • 是的,你真的想要`Int(arc4random_uniform(6)+1)`. (60认同)
  • 非常简单.我喜欢.给予好评!但实际骰子没有"0".在你的代码中,`diceRoll`可能是'0`.只是说...... (7认同)
  • probability = Int(arc4random_uniform(UInt32(total))) - 我也不得不投入UInt32 (5认同)
  • let randomElementInArray = Int(arc4random_uniform(array.count)) (4认同)

Cat*_*Man 421

使用标准库函数来获得高质量的随机数:random()或者random(),就像在Objective-C中一样.

他们是在random()模块,因此,如果您还没有进口random(),random()random()(其中进口为你),你将需要random().

Swift 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()
Run Code Online (Sandbox Code Playgroud)

  • arc4_random_uniform(5) - > 0或1或2或3或4 (24认同)
  • 我没有必要明确导入达尔文 (7认同)
  • 在我的Playground文件中,我需要导入Darwin,因为我没有导入任何其他内容. (3认同)
  • **警告**:[已显示RC4或arc4](https://en.wikipedia.org/wiki/RC4#Biased_outputs_of_the_RC4)[可与纯随机值区分开](https://en.wikipedia.org / wiki / Distinguishing_attack)。因此,尽管arc4(流密码)*在密码上*安全,但实际上并非如此。 (3认同)
  • @MaartenBodewes:不再与这个答案直接相关,但 arc4random 实际上并不在 macOS 或 BSD 上使用 RC4 密码,尽管它的名字如此。它在 macOS 上使用系统提供的 CSPRNG,在大多数 BSD 上使用 ChaCha20。Swift 的默认 RNG(如本答案中所使用)将其称为 macOS 上的实现细节,但在每个受支持的平台上使用适当的底层生成器。 (2认同)

jst*_*stn 116

编辑:已 更新为Swift 3.0

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
}
Run Code Online (Sandbox Code Playgroud)

我们可以使用这个新的泛型函数来扩展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
    }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,我们可以扩展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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

完成家庭......

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

毕竟,我们终于可以这样做了:

let diceRoll = UInt64.random(lower: 1, upper: 7)
Run Code Online (Sandbox Code Playgroud)


Gro*_*oot 74

编辑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)
Run Code Online (Sandbox Code Playgroud)

您也可以使用random(in:)其他原始值获取随机值; 比如Int,Double,Float甚至Bool.

Swift版本<4.2

此方法将Int在给定的最小值和最大值之间生成随机值

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
Run Code Online (Sandbox Code Playgroud)


小智 61

我用过这段代码:

var k: Int = random() % 10;
Run Code Online (Sandbox Code Playgroud)

  • 你必须先调用srandom(UInt32(time(nil))),否则它将始终返回相同的数字序列 (20认同)
  • 我在random()上读了两次apple应用程序,但无法收集它的用法......我希望它们只是在上面包含一个简单的代码示例."random()函数使用一个非线性,附加反馈,随机数生成器,使用一个大小为31的长整数的默认表.它返回0到(2**31)-1范围内的连续伪随机数.这个随机数发生器的周期非常大,约为16*((2**31)-1)." ...非常感谢苹果......我一定会在下一篇论文中提到这一点. (3认同)
  • 该解决方案具有模偏差:https://zuttobenkyou.wordpress.com/2012/10/18/generating-random-numbers-without-modulo-bias/ (2认同)

Two*_*aws 33

从iOS 9开始,您可以使用新的GameplayKit类以多种方式生成随机数.

您有四种源类型可供选择:一般随机源(未命名,下至系统选择它的作用),线性同余,ARC4和Mersenne Twister.这些可以产生随机的整数,浮点数和布尔值.

在最简单的级别,您可以从系统的内置随机源生成一个随机数,如下所示:

GKRandomSource.sharedRandom().nextInt()
Run Code Online (Sandbox Code Playgroud)

这产生了-2,147,483,648和2,147,483,647之间的数字.如果你想要一个介于0和上限(独占)之间的数字,你可以使用:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
Run Code Online (Sandbox Code Playgroud)

GameplayKit内置一些便利构造器来处理骰子.例如,您可以像这样滚动六面模具:

let d6 = GKRandomDistribution.d6()
d6.nextInt()
Run Code Online (Sandbox Code Playgroud)

另外,您可以使用GKShuffledDistribution之类的内容来塑造随机分布.这需要更多解释,但如果您有兴趣,可以阅读我的GameplayKit随机数教程.

  • 这个工具包有多重要导入?我不想膨胀我的代码. (7认同)

Dav*_*ong 25

你可以像在C中那样做:

let randomNumber = arc4random()
Run Code Online (Sandbox Code Playgroud)

randomNumber被推断为类型UInt32(32位无符号整数)

  • 附录:`rand`,`arc4random`,`drand48`和朋友都在`Darwin`模块中.如果您正在构建Cocoa,UIKit或Foundation应用程序,它已经为您导入,但您需要在操场上"导入Darwin". (12认同)
  • 并且不要尝试将arc4random()的结果转换为Int - 这在64位平台上可以正常工作,但在32位平台上,Int是32位签名的,所以你会得到意想不到的负面数字.这已经惹了几个人,所以我想我会在这里提到它. (5认同)

Sur*_*gch 23

使用 arc4random_uniform()

用法:

arc4random_uniform(someNumber: UInt32) -> UInt32

这使您可以在范围内的随机整数0someNumber - 1.

最大值为UInt324,294,967,295(即2^32 - 1).

例子:

一般形式:

let number = min + arc4random_uniform(max - min + 1)
Run Code Online (Sandbox Code Playgroud)

其中number,maxminUInt32.

关于什么...

arc4random()

您还可以使用arc4random()生成UInt320到2 ^ 32-1之间的随机数.因此,要获得0和之间的随机数x-1,您可以将其除以x并取余数.或者换句话说,使用剩余运算符(%):

let number = arc4random() % 5 // 0...4
Run Code Online (Sandbox Code Playgroud)

但是,这会产生轻微的模偏差(另请参见此处此处),因此arc4random_uniform()建议这样做.

转换为 Int

通常情况下这将是罚款,做这样的事情,以来回转换之间IntUInt32:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))
Run Code Online (Sandbox Code Playgroud)

但问题是,它Int具有一系列-2,147,483,648...2,147,483,64732位系统和一系列-9,223,372,036,854,775,808...9,223,372,036,854,775,80764位系统.将其与UInt32范围进行比较0...4,294,967,295.该UUInt32手段无符号.

请考虑以下错误:

UInt32(-1) // negative numbers cause integer overflow error
UInt32(4294967296) // numbers greater than 4,294,967,295 cause integer overflow error
Run Code Online (Sandbox Code Playgroud)

因此,您只需要确保输入参数在UInt32范围内,并且您不需要超出该范围的输出.


R.S*_*R.S 19

10(0-9)之间随机数的例子;

import UIKit

let randomNumber = Int(arc4random_uniform(10))
Run Code Online (Sandbox Code Playgroud)

非常简单的代码 - 简单而简短.


Con*_*nor 16

我已经能够用来rand()获得一个随机的CInt.您可以使用以下内容将其设为Int:

let myVar: Int = Int(rand())
Run Code Online (Sandbox Code Playgroud)

您可以使用自己喜欢的C随机函数,如果需要,只需将值转换为Int即可.

  • 请注意,如果您在使用rand()之前没有调用srand(...)(仅调用一次),则每次执行程序时,数字序列将始终完全相同.如果你不想这样,那么使用arc4random() (4认同)
  • 您还可以使用`random()`,它返回一个`Int`而不是`UInt32` - 就像提到的@SomeGuy一样,只需在任何地方调用`srandom(arc4random())`然后再使用它来确保它有一个不同的,每次执行程序的随机种子. (2认同)

Ryn*_*ang 16

@jstn的答案很好,但有点冗长.Swift被称为面向协议的语言,因此我们可以通过添加协议扩展的默认实现来实现相同的结果,而无需为整数族中的每个类实现样板代码.

public extension ExpressibleByIntegerLiteral {
    public static func arc4random() -> Self {
        var r: Self = 0
        arc4random_buf(&r, MemoryLayout<Self>.size)
        return r
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我们可以做到:

let i = Int.arc4random()
let j = UInt32.arc4random()
Run Code Online (Sandbox Code Playgroud)

和所有其他整数类都可以.


ARG*_*Geo 14

更新日期:2022 年 6 月 9 日。

斯威夫特 5.7

假设我们有一个数组:

let numbers: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
Run Code Online (Sandbox Code Playgroud)


对于 iOS 和 macOS,您可以在 Xcode 框架中使用系统范围的随机源GameKit。在这里你可以找到GKRandomSource类及其sharedRandom()类方法:

import GameKit

private func randomNumberGenerator() -> Int {
    let rand = GKRandomSource.sharedRandom().nextInt(upperBound: numbers.count)
    return numbers[rand]
}

randomNumberGenerator()
Run Code Online (Sandbox Code Playgroud)


您还可以使用randomElement()返回集合的随机元素的方法:

let randomNumber = numbers.randomElement()!
print(randomNumber)
Run Code Online (Sandbox Code Playgroud)


或者使用arc4random_uniform(). 注意这个方法返回UInt32类型。

let generator = Int(arc4random_uniform(11))
print(generator)
Run Code Online (Sandbox Code Playgroud)


当然,我们可以使用一个makeIterator()方法来返回集合元素的迭代器。

let iterator: Int = (1...10).makeIterator().shuffled().first!
print(iterator)
Run Code Online (Sandbox Code Playgroud)


您在此处看到的最后一个示例在 的帮助下返回指定范围内的随机值static func random(in range: ClosedRange<Int>) -> Int

let randomizer = Int.random(in: 1...10)
print(randomizer)
Run Code Online (Sandbox Code Playgroud)


伪随机双精度数字生成器drand48()返回 0.0 到 1.0 之间的值。

import Foundation

let randomInt = Int(drand48() * 10)
Run Code Online (Sandbox Code Playgroud)


Sh_*_*han 11

Swift 4.2中,您可以通过调用所需的random()任何数字类型的方法来生成随机数,从而提供您想要使用的范围.例如,这会生成1到9范围内的随机数,包括两侧

let randInt = Int.random(in: 1..<10)
Run Code Online (Sandbox Code Playgroud)

还有其他类型

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
Run Code Online (Sandbox Code Playgroud)


dem*_*lus 9

这是一个很好地完成工作的库 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
    }
}
Run Code Online (Sandbox Code Playgroud)


Raj*_*rma 8

 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}
Run Code Online (Sandbox Code Playgroud)


Jef*_*erg 6

我想补充一下现有的答案,即Swift本书中的随机数生成器示例是一个线性同余生成器(LCG),它是一个非常有限的一个,不应该是除了必须琐碎的例子,其中随机性的质量没有什么都不重要.并且LCG绝不应该用于加密目的.

arc4random()更好,可用于大多数目的,但不应再用于加密目的.

如果您想要保证加密安全的内容,请使用SecCopyRandomBytes().请注意,如果您将随机数生成器构建为某些内容,则其他人可能最终(误)将其用于加密目的(例如密码,密钥或盐生成),那么您应该考虑使用SecCopyRandomBytes(),即使您的需要不是非常需要.


Jak*_*lář 6

Swift 4.2起

有一组新的API:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
Run Code Online (Sandbox Code Playgroud)
  • 现在,所有数字类型都有采用的random(in:)方法range

  • 它返回在该范围内均匀分布的数字。


TL; DR

那么,“好的”旧方法有什么问题?

  1. 您必须使用导入的C API (它们在平台之间是不同的)

  2. 而且...

如果我告诉您随机不是那样怎么办?

如果使用arc4random() (计算余数)类似arc4random() % aNumber,则结果不会0和之间均匀分布aNumber。有一个问题叫做模偏差

模偏差

通常情况下,该函数生成之间的随机数0MAX (取决于类型等)。为了简单快速地举一个例子,假设最大数为,7并且您关心范围内的随机数0 ..< 2 (如果愿意,可以选择区间[0,3])

单个数字的概率为:

  • 0:3/8 = 37.5%
  • 1:3/8 = 37.5%
  • 2:2/8 = 25%

换句话说,您更有可能01而不是2结尾。当然,请记住,这是极其简化的,并且MAX数更高,使其更加“公平”。

此问题是由解决随机统一- SE-0202雨燕4.2


iSr*_*n27 6

斯威夫特 4.2

再见导入 Foundation C lib 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()
Run Code Online (Sandbox Code Playgroud)
  1. 您可以使用 random(in:) 从范围中生成随机数字。
  2. 如果范围为空,randomElement() 将返回 nil,因此您要解开返回的 Int 吗?与 if let 。
  3. 您可以使用 random(in:) 生成随机 Double、Float 或 CGFloat,并使用 random() 返回随机 Bool。

更多 @ 1sucai.com


Tar*_*oel 5

var randomNumber = Int(arc4random_uniform(UInt32(**5**)))
Run Code Online (Sandbox Code Playgroud)

这里5将确保生成随机数,但是从零到五.您可以相应地设置值.


bro*_*ino 5

在某些版本的Xcode中没有arc4Random_uniform()(在7.1中它运行但不为我自动完成).你可以这样做.

从0-5生成随机数.第一

import GameplayKit
Run Code Online (Sandbox Code Playgroud)

然后

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
Run Code Online (Sandbox Code Playgroud)