如何在苹果的Swift语言中生成随机数?

时间:2021-04-27 16:57:38

I realize the Swift book provided an implementation of a random number generator. Is the best practice to copy and paste this implementation in one's own program? Or is there a library that does this that we can use now?

我意识到斯威夫特的书提供了一个随机数生成器的实现。在自己的程序中复制和粘贴这个实现的最佳实践是什么?或者有我们现在可以使用的库吗?

24 个解决方案

#1


284  

Use the standard library functions for high quality random numbers: arc4random() or arc4random_uniform(), just as in Objective-C.

对于高质量随机数使用标准库函数:arc4random()或arc4random_uniform(),就像Objective-C中一样。

They are in the Darwin module, so if you haven't imported AppKit, UIKit, or Foundation (which import it for you), you will need to import Darwin.

它们在Darwin模块中,所以如果您没有导入AppKit、UIKit或Foundation(它为您导入),您将需要导入Darwin。

Swift 4.2

斯威夫特4.2

Swift 4.2 shipped with Xcode 10 introduces new easy-to-use random functions for many data types. You can call the random() method on numeric types.

随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()

#2


464  

Use arc4random_uniform(n) for a random integer between 0 and n-1.

对于0和n-1之间的随机整数,使用arc4random_uniform(n)。

let diceRoll = Int(arc4random_uniform(6) + 1)

Cast the result to Int so you don't have to explicitly type your vars as UInt32 (which seems un-Swifty).

将结果转换为Int类型,这样您就不必显式地将vars输入UInt32(看起来不太时髦)。

#3


112  

Edit: Updated for Swift 3.0

编辑:为Swift 3.0更新

arc4random works well in Swift, but the base functions are limited to 32-bit integer types (Int is 64-bit on iPhone 5S and modern Macs). Here's a generic function for a random number of a type expressible by an integer literal:

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
}

We can use this new generic function to extend UInt64, adding boundary arguments and mitigating modulo bias. (This is lifted straight from arc4random.c)

我们可以使用这个新的泛型函数来扩展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
    }
}

With that we can extend Int64 for the same arguments, dealing with overflow:

有了它,我们可以将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
        }
    }
}

To complete the family...

完整的家庭……

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
        }
    }
}

After all that, we can finally do something like this:

在这之后,我们终于可以做这样的事情:

let diceRoll = UInt64.random(lower: 1, upper: 7)

#4


67  

This method will generate a random Int value between the given minimum and maximum

该方法将在给定的最小值和最大值之间生成一个随机整数值

func randomInt(min: Int, max:Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

#5


58  

I used this code:

我用这段代码:

var k: Int = random() % 10;

#6


28  

As of iOS 9, you can use the new GameplayKit classes to generate random numbers in a variety of ways.

从ios9开始,您可以使用新的GameplayKit类以各种方式生成随机数。

You have four source types to choose from: a general random source (unnamed, down to the system to choose what it does), linear congruential, ARC4 and Mersenne Twister. These can generate random ints, floats and bools.

有四种源类型可供选择:一般的随机源(未命名的,直到系统选择它做什么),线性同余,ARC4和Mersenne Twister。它们可以生成随机的int、float和bools。

At the simplest level, you can generate a random number from the system's built-in random source like this:

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

GKRandomSource.sharedRandom().nextInt()

That generates a number between -2,147,483,648 and 2,147,483,647. If you want a number between 0 and an upper bound (exclusive) you'd use this:

这个数字在-2,147,483,648和2,147,483,647之间。如果你想要一个介于0和上限(排他性)之间的数字,你应该这样:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit has some convenience constructors built in to work with dice. For example, you can roll a six-sided die like this:

GameplayKit内置了一些方便的构造函数来使用骰子。例如,你可以像这样滚动一个六面骰子:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Plus you can shape the random distribution by using things like GKShuffledDistribution. That takes a little more explaining, but if you're interested you can read my tutorial on GameplayKit random numbers.

另外,你可以用GKShuffledDistribution这样的东西来塑造随机分布。这需要更多的解释,但如果你感兴趣的话,可以阅读我的关于GameplayKit随机数的教程。

#7


24  

You can do it the same way that you would in C:

你可以用C中的方法来做:

let randomNumber = arc4random()

randomNumber is inferred to be of type UInt32 (a 32-bit unsigned integer)

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

#8


18  

Use arc4random_uniform()

Usage:

用法:

arc4random_uniform(someNumber: UInt32) -> UInt32

arc4random_uniform(someNumber:UInt32)- > UInt32

This gives you random integers in the range 0 to someNumber - 1.

它给出了0到someNumber - 1的随机整数。

The maximum value for UInt32 is 4,294,967,295 (that is, 2^32 - 1).

UInt32的最大值是4294967295年(即2 ^ 32 - 1)。

Examples:

例子:

  • Coin flip

    抛硬币

    let flip = arc4random_uniform(2) // 0 or 1
    
  • Dice roll

    骰子滚

    let roll = arc4random_uniform(6) + 1 // 1...6
    
  • Random day in October

    随机一天10月

    let day = arc4random_uniform(31) + 1 // 1...31
    
  • Random year in the 1990s

    20世纪90年代的任意年份

    let year = 1990 + arc4random_uniform(10)
    

General form:

一般形式:

let number = min + arc4random_uniform(max - min + 1)

where number, max, and min are UInt32.

其中number、max、min为UInt32。

What about...

arc4random()

arc4random()

You can also get a random number by using arc4random(), which produces a UInt32 between 0 and 2^32-1. Thus to get a random number between 0 and x-1, you can divide it by x and take the remainder. Or in other words, use the Remainder Operator (%):

你也可以被使用一个随机数arc4random(),产生0和2之间UInt32 ^ 32-1。为了得到0和x-1之间的随机数,你可以把它除以x,然后取余数。或者换句话说,使用余数运算符(%):

let number = arc4random() % 5 // 0...4

However, this produces the slight modulo bias (see also here and here), so that is why arc4random_uniform() is recommended.

但是,这会产生轻微的模块偏差(请参见这里和这里),因此推荐使用arc4random_uniform()。

Converting to and from Int

转换到和从Int

Normally it would be fine to do something like this in order to convert back and forth between Int and UInt32:

通常情况下,可以这样做,以便在Int和UInt32之间来回转换:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

The problem, though, is that Int has a range of -2,147,483,648...2,147,483,647 on 32 bit systems and a range of -9,223,372,036,854,775,808...9,223,372,036,854,775,807 on 64 bit systems. Compare this to the UInt32 range of 0...4,294,967,295. The U of UInt32 means unsigned.

但是,问题是Int的范围是-2,147,483,648。32位系统的2,147,483,647,范围为-9,223,372,036,854,775,808…64位系统的9,223,372,036,854,775,807。相比之下,UInt32的范围为0…4,294,967,295。UInt32的U表示无符号。

Consider the following errors:

考虑下面的错误:

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

So you just need to be sure that your input parameters are within the UInt32 range and that you don't need an output that is outside of that range either.

所以你只需要确定你的输入参数在UInt32范围内,并且你不需要在这个范围之外的输出。

#9


16  

I've been able to just use rand() to get a random CInt. You can make it an Int by using something like this:

我可以使用rand()来得到一个随机的CInt。您可以使用如下方法将其设置为Int:

let myVar: Int = Int(rand())

You can use your favourite C random function, and just convert to value to Int if needed.

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

#10


16  

@jstn's answer is good, but a bit verbose. Swift is known as a protocol-oriented language, so we can achieve the same result without having to implement boilerplate code for every class in the integer family, by adding a default implementation for the protocol extension.

@jstn的答案很好,但是有点啰嗦。Swift是一种面向协议的语言,因此我们可以实现相同的结果,而不必为整型家族中的每个类实现样板代码,只需为协议扩展添加一个默认实现。

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

Now we can do:

现在我们能做的:

let i = Int.arc4random()
let j = UInt32.arc4random()

and all other integer classes are ok.

所有其他整数类都可以。

#11


15  

Example for random number in between 10 (0-9);

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

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Very easy code - simple and short.

非常简单的代码-简单和简短。

#12


9  

Here is a library that does the job well https://github.com/thellimist/SwiftRandom

这里有一个库可以很好地完成这项工作: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
    }
}

#13


8  

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

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}

#14


7  

In Swift 4.2 you can generate random numbers by calling the random() method on whatever numeric type you want, providing the range you want to work with. For example, this generates a random number in the range 1 through 9, inclusive on both sides

在Swift 4.2中,您可以通过调用random()方法来生成随机数,无论您想要什么类型的数值,并提供您想要使用的范围。例如,它生成一个范围为1到9的随机数,两边都包含

let randInt = Int.random(in: 1..<10)

Also with other types

还与其他类型

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)

#15


6  

I would like to add to existing answers that the random number generator example in the Swift book is a Linear Congruence Generator (LCG), it is a severely limited one and shouldn't be except for the must trivial examples, where quality of randomness doesn't matter at all. And a LCG should never be used for cryptographic purposes.

我想补充一下现有的答案,即斯威夫特书中的随机数生成器示例是一个线性同余生成器(LCG),它是一个严重受限的示例,除了那些必须的琐碎示例之外,不应该是这样的,因为随机性的质量根本不重要。而且LCG不应该用于加密目的。

arc4random() is much better and can be used for most purposes, but again should not be used for cryptographic purposes.

arc4random()要好得多,可以用于大多数目的,但同样不能用于加密目的。

If you want something that is guaranteed to be cryptographically secure, use SecCopyRandomBytes(). Note that if you build a random number generator into something, someone else might end up (mis)-using it for cryptographic purposes (such as password, key or salt generation), then you should consider using SecCopyRandomBytes() anyway, even if your need doesn't quite require that.

如果您想要保证具有密码安全性的东西,请使用SecCopyRandomBytes()。注意,如果您将一个随机数生成器构建到某样东西中,那么其他人可能最终(mis)—将它用于加密目的(如密码、密钥或盐类生成),那么无论如何,您应该考虑使用SecCopyRandomBytes(),即使您的需要并不需要它。

#16


5  

var randomNumber = Int(arc4random_uniform(UInt32(**5**)))

Here 5 will make sure that the random number is generated though zero to five. You can set the value accordingly.

这里的5将确保从0到5生成随机数。您可以相应地设置值。

#17


5  

Without arc4Random_uniform() in some versions of Xcode(in 7.1 it runs but doesn't autocomplete for me). You can do this instead.

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

To generate a random number from 0-5. First

从0-5生成随机数。第一个

import GameplayKit

Then

然后

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

#18


2  

The following code will produce a secure random number between 0 and 255:

下面的代码将产生一个安全的随机数在0到255之间:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

You call it like this:

你这样称呼它:

print(UInt8.random)

For bigger numbers it becomes more complicated.
This is the best I could come up with:

对于更大的数字,它变得更加复杂。这是我能想到的最好的办法:

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) }
  }
}

These methods use an extra random number to determine how many UInt8s are going to be used to create the random number. The last line converts the [UInt8] to UInt16 or UInt32.

这些方法使用一个额外的随机数来确定将使用多少UInt8s来创建随机数。最后一行将[UInt8]转换为UInt16或UInt32。

I don't know if the last two still count as truly random, but you can tweak it to your likings :)

我不知道最后两个人是否还算真正的随机,但你可以把它调整成你的喜好:)

#19


2  

Details

xCode 9.1, Swift 4

xCode 9.1,斯威夫特4

Math oriented solution (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
}

Usage of solution (1)

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]

Programmers oriented solution (2)

Do not forget to add Math oriented solution (1) code here

不要忘记在这里添加面向数学的解决方案(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]
    }
}

Usage of solution (2)

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]

Full Sample

Do not forget to add solution (1) and solution (2) codes here

不要忘记在这里添加解决方案(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]
}

Sample result

如何在苹果的Swift语言中生成随机数?

#20


2  

Since Swift 4.2

TL;DR There is a new set of APIs:

有一套新的空气污染指数:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • All numeric types now have the random(in:) method that takes range.

    所有数值类型现在都有一个随机(in:)方法,该方法接受范围。

  • It returns a number uniformly distributed in that range.

    它返回一个均匀分布在这个范围内的数字。


Well, what is wrong with the "good" old way?

  1. You have to use imported C APIs (They are different between platforms).

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

  2. And moreover...

    而且……

What if I told you that the random is not that random?

如果我告诉你随机不是随机的呢?

If you use arc4random() (to calculate the remainder) like arc4random() % aNumber, the result is not uniformly distributed between the 0 and aNumber. There is a problem called the Modulo bias.

如果您使用arc4random()()(计算余数),如arc4random() % aNumber,那么结果不会均匀地分布在0和aNumber之间。有一个问题叫做模块化偏差。

Modulo bias

模的偏见

Normally, the function generates a random number between 0 and MAX (depends on the type etc.). To make a quick, easy example, let's say the max number is 7 and you care about a random number in the range 0 ..< 2 (or the interval [0, 3) if you prefer that).

通常,函数会生成0到MAX之间的随机数(取决于类型等)。举个简单的例子,假设最大值是7,你关心的是0范围内的一个随机数。< 2(或区间[0,3)如果你喜欢的话)。

The probabilities for individual numbers are:

个别数字的概率为:

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

In other words, you are more likely to end up with 0 or 1 than 2. Of course, bare in mind that this is extremely simplified and the MAX number is much higher, making it more "fair".

换句话说,你更有可能得到0或1而不是2。当然,请记住,这是极其简化的,最大数量要高得多,使它更“公平”。

This problem is addressed by SE-0202 - Random unification in Swift 4.2

这个问题由Swift 4.2中的SE-0202 - Random unification解决

#21


1  

Swift 4.2

斯威夫特4.2

Swift 4.2 has included a native and fairly full-featured random number API in the standard library. (Swift Evolution proposal SE-0202)

Swift 4.2在标准库中包含了一个本地的、功能相当全面的随机数API。(快速进化的提议se - 0202)

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

All number types have the static random(in:) which takes the range and returns the random number in the given range

所有的数字类型都具有静态随机(in:),它获取范围并返回给定范围内的随机数

#22


0  

You can use GeneratorOf like this:

你可以这样使用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())

#23


0  

I use this code to generate a random number:

我使用此代码生成一个随机数:

//
//  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]
    }
}

#24


0  

For iOS, macOS and tvOS you can use system-wide random source in Xcode's framework GameKit. Here you can find GKRandomSource class with its sharedRandom() class method:

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

import GameKit

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func randomGenerator() -> Int {
    let random = GKRandomSource.sharedRandom().nextInt(upperBound: number.count)
    return number[random]
}

It's written in Swift 4.2.

它是用Swift 4.2写的。

#1


284  

Use the standard library functions for high quality random numbers: arc4random() or arc4random_uniform(), just as in Objective-C.

对于高质量随机数使用标准库函数:arc4random()或arc4random_uniform(),就像Objective-C中一样。

They are in the Darwin module, so if you haven't imported AppKit, UIKit, or Foundation (which import it for you), you will need to import Darwin.

它们在Darwin模块中,所以如果您没有导入AppKit、UIKit或Foundation(它为您导入),您将需要导入Darwin。

Swift 4.2

斯威夫特4.2

Swift 4.2 shipped with Xcode 10 introduces new easy-to-use random functions for many data types. You can call the random() method on numeric types.

随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()

#2


464  

Use arc4random_uniform(n) for a random integer between 0 and n-1.

对于0和n-1之间的随机整数,使用arc4random_uniform(n)。

let diceRoll = Int(arc4random_uniform(6) + 1)

Cast the result to Int so you don't have to explicitly type your vars as UInt32 (which seems un-Swifty).

将结果转换为Int类型,这样您就不必显式地将vars输入UInt32(看起来不太时髦)。

#3


112  

Edit: Updated for Swift 3.0

编辑:为Swift 3.0更新

arc4random works well in Swift, but the base functions are limited to 32-bit integer types (Int is 64-bit on iPhone 5S and modern Macs). Here's a generic function for a random number of a type expressible by an integer literal:

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
}

We can use this new generic function to extend UInt64, adding boundary arguments and mitigating modulo bias. (This is lifted straight from arc4random.c)

我们可以使用这个新的泛型函数来扩展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
    }
}

With that we can extend Int64 for the same arguments, dealing with overflow:

有了它,我们可以将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
        }
    }
}

To complete the family...

完整的家庭……

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
        }
    }
}

After all that, we can finally do something like this:

在这之后,我们终于可以做这样的事情:

let diceRoll = UInt64.random(lower: 1, upper: 7)

#4


67  

This method will generate a random Int value between the given minimum and maximum

该方法将在给定的最小值和最大值之间生成一个随机整数值

func randomInt(min: Int, max:Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}

#5


58  

I used this code:

我用这段代码:

var k: Int = random() % 10;

#6


28  

As of iOS 9, you can use the new GameplayKit classes to generate random numbers in a variety of ways.

从ios9开始,您可以使用新的GameplayKit类以各种方式生成随机数。

You have four source types to choose from: a general random source (unnamed, down to the system to choose what it does), linear congruential, ARC4 and Mersenne Twister. These can generate random ints, floats and bools.

有四种源类型可供选择:一般的随机源(未命名的,直到系统选择它做什么),线性同余,ARC4和Mersenne Twister。它们可以生成随机的int、float和bools。

At the simplest level, you can generate a random number from the system's built-in random source like this:

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

GKRandomSource.sharedRandom().nextInt()

That generates a number between -2,147,483,648 and 2,147,483,647. If you want a number between 0 and an upper bound (exclusive) you'd use this:

这个数字在-2,147,483,648和2,147,483,647之间。如果你想要一个介于0和上限(排他性)之间的数字,你应该这样:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit has some convenience constructors built in to work with dice. For example, you can roll a six-sided die like this:

GameplayKit内置了一些方便的构造函数来使用骰子。例如,你可以像这样滚动一个六面骰子:

let d6 = GKRandomDistribution.d6()
d6.nextInt()

Plus you can shape the random distribution by using things like GKShuffledDistribution. That takes a little more explaining, but if you're interested you can read my tutorial on GameplayKit random numbers.

另外,你可以用GKShuffledDistribution这样的东西来塑造随机分布。这需要更多的解释,但如果你感兴趣的话,可以阅读我的关于GameplayKit随机数的教程。

#7


24  

You can do it the same way that you would in C:

你可以用C中的方法来做:

let randomNumber = arc4random()

randomNumber is inferred to be of type UInt32 (a 32-bit unsigned integer)

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

#8


18  

Use arc4random_uniform()

Usage:

用法:

arc4random_uniform(someNumber: UInt32) -> UInt32

arc4random_uniform(someNumber:UInt32)- > UInt32

This gives you random integers in the range 0 to someNumber - 1.

它给出了0到someNumber - 1的随机整数。

The maximum value for UInt32 is 4,294,967,295 (that is, 2^32 - 1).

UInt32的最大值是4294967295年(即2 ^ 32 - 1)。

Examples:

例子:

  • Coin flip

    抛硬币

    let flip = arc4random_uniform(2) // 0 or 1
    
  • Dice roll

    骰子滚

    let roll = arc4random_uniform(6) + 1 // 1...6
    
  • Random day in October

    随机一天10月

    let day = arc4random_uniform(31) + 1 // 1...31
    
  • Random year in the 1990s

    20世纪90年代的任意年份

    let year = 1990 + arc4random_uniform(10)
    

General form:

一般形式:

let number = min + arc4random_uniform(max - min + 1)

where number, max, and min are UInt32.

其中number、max、min为UInt32。

What about...

arc4random()

arc4random()

You can also get a random number by using arc4random(), which produces a UInt32 between 0 and 2^32-1. Thus to get a random number between 0 and x-1, you can divide it by x and take the remainder. Or in other words, use the Remainder Operator (%):

你也可以被使用一个随机数arc4random(),产生0和2之间UInt32 ^ 32-1。为了得到0和x-1之间的随机数,你可以把它除以x,然后取余数。或者换句话说,使用余数运算符(%):

let number = arc4random() % 5 // 0...4

However, this produces the slight modulo bias (see also here and here), so that is why arc4random_uniform() is recommended.

但是,这会产生轻微的模块偏差(请参见这里和这里),因此推荐使用arc4random_uniform()。

Converting to and from Int

转换到和从Int

Normally it would be fine to do something like this in order to convert back and forth between Int and UInt32:

通常情况下,可以这样做,以便在Int和UInt32之间来回转换:

let number: Int = 10
let random = Int(arc4random_uniform(UInt32(number)))

The problem, though, is that Int has a range of -2,147,483,648...2,147,483,647 on 32 bit systems and a range of -9,223,372,036,854,775,808...9,223,372,036,854,775,807 on 64 bit systems. Compare this to the UInt32 range of 0...4,294,967,295. The U of UInt32 means unsigned.

但是,问题是Int的范围是-2,147,483,648。32位系统的2,147,483,647,范围为-9,223,372,036,854,775,808…64位系统的9,223,372,036,854,775,807。相比之下,UInt32的范围为0…4,294,967,295。UInt32的U表示无符号。

Consider the following errors:

考虑下面的错误:

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

So you just need to be sure that your input parameters are within the UInt32 range and that you don't need an output that is outside of that range either.

所以你只需要确定你的输入参数在UInt32范围内,并且你不需要在这个范围之外的输出。

#9


16  

I've been able to just use rand() to get a random CInt. You can make it an Int by using something like this:

我可以使用rand()来得到一个随机的CInt。您可以使用如下方法将其设置为Int:

let myVar: Int = Int(rand())

You can use your favourite C random function, and just convert to value to Int if needed.

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

#10


16  

@jstn's answer is good, but a bit verbose. Swift is known as a protocol-oriented language, so we can achieve the same result without having to implement boilerplate code for every class in the integer family, by adding a default implementation for the protocol extension.

@jstn的答案很好,但是有点啰嗦。Swift是一种面向协议的语言,因此我们可以实现相同的结果,而不必为整型家族中的每个类实现样板代码,只需为协议扩展添加一个默认实现。

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

Now we can do:

现在我们能做的:

let i = Int.arc4random()
let j = UInt32.arc4random()

and all other integer classes are ok.

所有其他整数类都可以。

#11


15  

Example for random number in between 10 (0-9);

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

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Very easy code - simple and short.

非常简单的代码-简单和简短。

#12


9  

Here is a library that does the job well https://github.com/thellimist/SwiftRandom

这里有一个库可以很好地完成这项工作: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
    }
}

#13


8  

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

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}

#14


7  

In Swift 4.2 you can generate random numbers by calling the random() method on whatever numeric type you want, providing the range you want to work with. For example, this generates a random number in the range 1 through 9, inclusive on both sides

在Swift 4.2中,您可以通过调用random()方法来生成随机数,无论您想要什么类型的数值,并提供您想要使用的范围。例如,它生成一个范围为1到9的随机数,两边都包含

let randInt = Int.random(in: 1..<10)

Also with other types

还与其他类型

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)

#15


6  

I would like to add to existing answers that the random number generator example in the Swift book is a Linear Congruence Generator (LCG), it is a severely limited one and shouldn't be except for the must trivial examples, where quality of randomness doesn't matter at all. And a LCG should never be used for cryptographic purposes.

我想补充一下现有的答案,即斯威夫特书中的随机数生成器示例是一个线性同余生成器(LCG),它是一个严重受限的示例,除了那些必须的琐碎示例之外,不应该是这样的,因为随机性的质量根本不重要。而且LCG不应该用于加密目的。

arc4random() is much better and can be used for most purposes, but again should not be used for cryptographic purposes.

arc4random()要好得多,可以用于大多数目的,但同样不能用于加密目的。

If you want something that is guaranteed to be cryptographically secure, use SecCopyRandomBytes(). Note that if you build a random number generator into something, someone else might end up (mis)-using it for cryptographic purposes (such as password, key or salt generation), then you should consider using SecCopyRandomBytes() anyway, even if your need doesn't quite require that.

如果您想要保证具有密码安全性的东西,请使用SecCopyRandomBytes()。注意,如果您将一个随机数生成器构建到某样东西中,那么其他人可能最终(mis)—将它用于加密目的(如密码、密钥或盐类生成),那么无论如何,您应该考虑使用SecCopyRandomBytes(),即使您的需要并不需要它。

#16


5  

var randomNumber = Int(arc4random_uniform(UInt32(**5**)))

Here 5 will make sure that the random number is generated though zero to five. You can set the value accordingly.

这里的5将确保从0到5生成随机数。您可以相应地设置值。

#17


5  

Without arc4Random_uniform() in some versions of Xcode(in 7.1 it runs but doesn't autocomplete for me). You can do this instead.

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

To generate a random number from 0-5. First

从0-5生成随机数。第一个

import GameplayKit

Then

然后

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

#18


2  

The following code will produce a secure random number between 0 and 255:

下面的代码将产生一个安全的随机数在0到255之间:

extension UInt8 {
  public static var random: UInt8 {
    var number: UInt8 = 0
    _ = SecRandomCopyBytes(kSecRandomDefault, 1, &number)
    return number
  }
}

You call it like this:

你这样称呼它:

print(UInt8.random)

For bigger numbers it becomes more complicated.
This is the best I could come up with:

对于更大的数字,它变得更加复杂。这是我能想到的最好的办法:

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) }
  }
}

These methods use an extra random number to determine how many UInt8s are going to be used to create the random number. The last line converts the [UInt8] to UInt16 or UInt32.

这些方法使用一个额外的随机数来确定将使用多少UInt8s来创建随机数。最后一行将[UInt8]转换为UInt16或UInt32。

I don't know if the last two still count as truly random, but you can tweak it to your likings :)

我不知道最后两个人是否还算真正的随机,但你可以把它调整成你的喜好:)

#19


2  

Details

xCode 9.1, Swift 4

xCode 9.1,斯威夫特4

Math oriented solution (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
}

Usage of solution (1)

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]

Programmers oriented solution (2)

Do not forget to add Math oriented solution (1) code here

不要忘记在这里添加面向数学的解决方案(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]
    }
}

Usage of solution (2)

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]

Full Sample

Do not forget to add solution (1) and solution (2) codes here

不要忘记在这里添加解决方案(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]
}

Sample result

如何在苹果的Swift语言中生成随机数?

#20


2  

Since Swift 4.2

TL;DR There is a new set of APIs:

有一套新的空气污染指数:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • All numeric types now have the random(in:) method that takes range.

    所有数值类型现在都有一个随机(in:)方法,该方法接受范围。

  • It returns a number uniformly distributed in that range.

    它返回一个均匀分布在这个范围内的数字。


Well, what is wrong with the "good" old way?

  1. You have to use imported C APIs (They are different between platforms).

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

  2. And moreover...

    而且……

What if I told you that the random is not that random?

如果我告诉你随机不是随机的呢?

If you use arc4random() (to calculate the remainder) like arc4random() % aNumber, the result is not uniformly distributed between the 0 and aNumber. There is a problem called the Modulo bias.

如果您使用arc4random()()(计算余数),如arc4random() % aNumber,那么结果不会均匀地分布在0和aNumber之间。有一个问题叫做模块化偏差。

Modulo bias

模的偏见

Normally, the function generates a random number between 0 and MAX (depends on the type etc.). To make a quick, easy example, let's say the max number is 7 and you care about a random number in the range 0 ..< 2 (or the interval [0, 3) if you prefer that).

通常,函数会生成0到MAX之间的随机数(取决于类型等)。举个简单的例子,假设最大值是7,你关心的是0范围内的一个随机数。< 2(或区间[0,3)如果你喜欢的话)。

The probabilities for individual numbers are:

个别数字的概率为:

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

In other words, you are more likely to end up with 0 or 1 than 2. Of course, bare in mind that this is extremely simplified and the MAX number is much higher, making it more "fair".

换句话说,你更有可能得到0或1而不是2。当然,请记住,这是极其简化的,最大数量要高得多,使它更“公平”。

This problem is addressed by SE-0202 - Random unification in Swift 4.2

这个问题由Swift 4.2中的SE-0202 - Random unification解决

#21


1  

Swift 4.2

斯威夫特4.2

Swift 4.2 has included a native and fairly full-featured random number API in the standard library. (Swift Evolution proposal SE-0202)

Swift 4.2在标准库中包含了一个本地的、功能相当全面的随机数API。(快速进化的提议se - 0202)

let intBetween0to9 = Int.random(in: 0...9) 
let doubleBetween0to1 = Double.random(in: 0...1)

All number types have the static random(in:) which takes the range and returns the random number in the given range

所有的数字类型都具有静态随机(in:),它获取范围并返回给定范围内的随机数

#22


0  

You can use GeneratorOf like this:

你可以这样使用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())

#23


0  

I use this code to generate a random number:

我使用此代码生成一个随机数:

//
//  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]
    }
}

#24


0  

For iOS, macOS and tvOS you can use system-wide random source in Xcode's framework GameKit. Here you can find GKRandomSource class with its sharedRandom() class method:

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

import GameKit

let number: [Int] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

func randomGenerator() -> Int {
    let random = GKRandomSource.sharedRandom().nextInt(upperBound: number.count)
    return number[random]
}

It's written in Swift 4.2.

它是用Swift 4.2写的。