Comment générer un nombre aléatoire dans le langage Swift D'Apple?

je réalise que le livre Swift a fourni une implémentation d'un générateur de nombres aléatoires. Est-ce que la meilleure pratique consiste à copier et coller cette implémentation dans son propre programme? Ou est-il une bibliothèque qui fait ce que nous pouvons utiliser aujourd'hui?

375
demandé sur timbo 2014-06-03 08:27:24

25 réponses

utiliser les fonctions de bibliothèque standard pour les nombres aléatoires de haute qualité: arc4random() ou arc4random_uniform() , comme dans L'objectif-C.

ils sont dans le module Darwin , donc si vous n'avez pas importé AppKit , UIKit , ou Foundation (qui l'importent pour vous), vous aurez besoin de import Darwin .

Swift 4.2

Swift 4.2 livré avec Xcode 10 introduit une nouvelle facilité d'utilisation aléatoire fonctions pour de nombreux types de données. Vous pouvez appeler la méthode random() sur les types numériques.

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
316
répondu Catfish_Man 2018-06-17 19:07:35

utilisez arc4random_uniform(n) pour un entier aléatoire entre 0 et n-1.

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

lance le résultat à Int de sorte que vous n'ayez pas à taper explicitement vos vars comme UInt32 (ce qui semble non-Swifty).

487
répondu John Pavley 2018-04-23 13:54:21

modifier: mise à jour pour Swift 3.0

arc4random fonctionne bien dans Swift, mais les fonctions de base sont limitées aux types entiers 32 bits ( Int est 64 bits sur iPhone 5S et Macs modernes). Voici une fonction générique pour un nombre aléatoire d'un type exprimable par un entier littéral:

public func arc4random<T: ExpressibleByIntegerLiteral>(_ type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, MemoryLayout<T>.size)
    return r
}

nous pouvons utiliser cette nouvelle fonction générique pour étendre UInt64 , en ajoutant des arguments de limites et atténuer le biais modulo. (Ceci est soulevé directement de 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
    }
}

Avec que nous pouvons étendre Int64 pour les mêmes arguments, traitant de débordement:

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

Pour compléter la famille...

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

Après tout cela, nous pouvons enfin faire quelque chose comme ceci:

let diceRoll = UInt64.random(lower: 1, upper: 7)
113
répondu jstn 2016-09-07 00:10:27

Modifier pour Swift 4.2

à partir de Swift 4.2, au lieu d'utiliser la fonction C importée arc4random_uniform(), vous pouvez maintenant utiliser les propres fonctions natives de Swift.

// Generates integers starting with 0 up to, and including, 10
Int.random(in: 0 ... 10)

vous pouvez utiliser random(in:) pour obtenir des valeurs aléatoires pour d'autres valeurs primitives aussi bien; telles que Int, Double, Float et même Bool.

versions Swift < 4.2

cette méthode générera une valeur aléatoire Int entre le minimum et le maximum donnés

func randomInt(min: Int, max: Int) -> Int {
    return min + Int(arc4random_uniform(UInt32(max - min + 1)))
}
67
répondu Groot 2018-10-13 18:14:36

j'ai utilisé ce code:

var k: Int = random() % 10;
58
répondu fockus 2015-04-21 09:26:36

à partir de iOS 9, Vous pouvez utiliser les nouvelles classes GameplayKit pour générer des nombres aléatoires de différentes façons.

vous avez quatre types de sources à choisir: une source aléatoire générale (unnamed, down to the system to choose what it does), linéaire congruential, ARC4 et Mersenne Twister. Ceux-ci peuvent générer des entiers, des flotteurs et des booléens.

au niveau le plus simple, vous pouvez générer un nombre aléatoire à partir de la source aléatoire intégrée du système comme ceci:

GKRandomSource.sharedRandom().nextInt()

qui génère un nombre entre -2.147.483.648 et 2.147.483.647. Si vous voulez un nombre entre 0 et une limite supérieure (exclusive) vous utiliserez ceci:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit a quelques constructeurs de commodité intégrés pour travailler avec des dés. Par exemple, vous pouvez rouler un dé à six faces comme ceci:

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

Plus vous pouvez façonner la distribution aléatoire en utilisant des choses comme GKShuffledDistribution. Qui prend un un peu plus d'explications, mais si vous êtes intéressé vous pouvez lire mon tutoriel sur GameplayKit nombres aléatoires .

31
répondu TwoStraws 2015-07-03 23:13:41

, Vous pouvez le faire de la même manière que vous le feriez dans C:

let randomNumber = arc4random()

randomNumber est présumé être de type UInt32 (un entier non signé de 32 bits)

24
répondu Dave DeLong 2014-06-03 04:31:42

utiliser arc4random_uniform()

Utilisation:

arc4random_uniform(someNumber: UInt32) -> UInt32

cela vous donne des entiers aléatoires dans la gamme 0 à someNumber - 1 .

la valeur maximale pour UInt32 est de 4 294 967 295 (c'est-à-dire 2^32 - 1 ).

exemples:

  • Coin flip

    let flip = arc4random_uniform(2) // 0 or 1
    
  • lancer de Dés

    let roll = arc4random_uniform(6) + 1 // 1...6
    
  • Random jour en octobre

    let day = arc4random_uniform(31) + 1 // 1...31
    
  • année aléatoire dans les années 1990

    let year = 1990 + arc4random_uniform(10)
    

forme Générale:

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

number , max , et min sont UInt32 .

Et alors?..

arc4random ()

vous pouvez également obtenir un nombre aléatoire en utilisant arc4random() , qui produit un UInt32 entre 0 et 2^32-1. Ainsi, pour obtenir un nombre aléatoire entre 0 et x-1 , vous pouvez le diviser par x et prendre le reste. Ou en d'autres termes, utiliser le reste opérateur ( % ) :

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

cependant, cela produit le léger modulo bias (voir aussi ici et ici ), c'est pourquoi arc4random_uniform() est recommandé.

conversion en et de Int

normalement, il serait bien de faire quelque chose comme cela afin de convertir en va-et-vient entre Int et UInt32 :

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

le problème, cependant, est que Int a une gamme de -2,147,483,648...2,147,483,647 sur les systèmes 32 bits et une gamme de -9,223,372,036,854,775,808...9,223,372,036,854,775,807 sur les systèmes 64 bits. Comparez cela à la gamme UInt32 de 0...4,294,967,295 . Le U de UInt32 signifie non signé .

considérer les erreurs suivantes:

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

Donc, vous avez juste besoin d'être sûr que votre entrée les paramètres sont dans le UInt32 et que vous n'avez pas besoin d'une sortie en dehors de cette plage.

21
répondu Suragch 2017-05-23 10:31:37

exemple pour nombre aléatoire entre 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Code très facile-simple et court.

17
répondu R.S 2016-01-02 16:52:54

j'ai pu juste utiliser rand() pour obtenir une CInt aléatoire. Vous pouvez faire un Int en utilisant quelque chose comme ceci:

let myVar: Int = Int(rand())

vous pouvez utiliser votre fonction de C aléatoire préféré, et juste convertir en valeur en Int si nécessaire.

16
répondu Connor 2016-05-04 09:18:59

la réponse de @jstn est bonne, mais un peu verbeuse. Swift est connu comme un langage orienté protocole, nous pouvons donc obtenir le même résultat sans avoir à implémenter du code boilerplate pour chaque classe de la famille integer, en ajoutant une implémentation par défaut pour l'extension du protocole.

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

Maintenant, nous pouvons faire:

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

et toutes les autres classes entières sont ok.

16
répondu Ryne Wang 2017-05-23 12:10:48

dans Swift 4.2 vous pouvez générer des nombres aléatoires en appelant la méthode random() sur n'importe quel type numérique que vous voulez, en fournissant la gamme que vous voulez travailler avec. Par exemple, cela génère un nombre aléatoire dans la gamme de 1 à 9, inclus des deux côtés

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

également avec d'autres types

let randFloat = Float.random(in: 1..<20)
let randDouble = Double.random(in: 1...30)
let randCGFloat = CGFloat.random(in: 1...40)
10
répondu Sh_Khan 2018-05-25 10:53:39

Voici une bibliothèque qui fait bien le travail 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
    }
}
9
répondu demiculus 2015-10-14 09:52:58
 let MAX : UInt32 = 9
 let MIN : UInt32 = 1

    func randomNumber()
{
    var random_number = Int(arc4random_uniform(MAX) + MIN)
    print ("random = ", random_number);
}
8
répondu Rajesh Sharma 2016-01-20 12:16:19

je voudrais ajouter aux réponses existantes que l'exemple du générateur de nombres aléatoires dans le livre Swift est un générateur de Congruence linéaire (LCG), il est sévèrement limité et ne devrait pas être excepté pour les exemples triviaux obligatoires, où la qualité de l'aléatoire n'importe pas du tout. Et un LCG ne doit jamais être utilisé à des fins cryptographiques .

arc4random() est beaucoup mieux et peut être utilisé pour la plupart des besoins, mais encore une fois ne devrait pas être utilisé à des fins cryptographiques.

si vous voulez quelque chose qui est garanti d'être cryptographiquement sûr, utilisez SecCopyRandomBytes() . Notez que si vous construisez un générateur de nombres aléatoires dans quelque chose, quelqu'un d'autre pourrait finir par l'utiliser (mis)-à des fins de cryptographie (tel que mot de passe, clé ou génération de sel), alors vous devriez envisager d'utiliser SecCopyRandomBytes() de toute façon, même si votre besoin ne l'exige pas tout à fait.

6
répondu Jeffrey Goldberg 2015-06-14 17:42:22
var randomNumber = Int(arc4random_uniform(UInt32(**5**)))

ici 5 va s'assurer que le nombre aléatoire est généré bien que zéro à cinq. Vous pouvez définir la valeur en conséquence.

5
répondu Taran Goel 2015-06-01 10:06:01

sans arc4Random_uniform () dans certaines versions de Xcode(dans 7.1 il tourne mais ne s'exécute pas pour moi). Vous pouvez le faire à la place.

pour générer un nombre aléatoire de 0-5. Premier

import GameplayKit

puis

let diceRoll = GKRandomSource.sharedRandom().nextIntWithUpperBound(6)
5
répondu brokenrhino 2015-10-30 02:39:50

Depuis Swift 4.2

il y a un nouvel ensemble D'API:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • tous numérique les types ont maintenant le random(in:) méthode qui prend range .

  • il renvoie un nombre uniformément distribué dans cette fourchette.


TL; DR

Eh bien, qu'est-ce qui ne va pas avec la bonne vieille méthode?

  1. Vous devez utiliser importés C Api (Elles sont différentes entre les plates-formes) .

  2. et de plus...

et si je vous disais que le hasard n'est pas aléatoire?

si vous utilisez arc4random() (pour calculer le reste) comme arc4random() % aNumber , le résultat n'est pas uniformément distribué entre le 0 et aNumber . Il y a un problème appelé le Modulo biais .

Modulo biais

Normalement, le fonction génère un nombre aléatoire entre 0 et MAX (dépend du type etc.) . Pour faire un exemple rapide et facile, disons que le nombre max est 7 et vous vous souciez d'un nombre aléatoire dans la gamme 0 ..< 2 (ou l'intervalle [0, 3) Si vous préférez que) .

les probabilités pour les nombres individuels sont:

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

en d'autres termes, vous êtes plus susceptible de finir avec 0 ou 1 que 2 . Bien sûr, à l'esprit que cela est extrêmement simplifié et le Le nombre MAX est beaucoup plus élevé, ce qui le rend plus"juste".

Ce problème est abordé par SE-0202 - Aléatoire unification dans "1519110920 Swift" 4.2

4
répondu Jakub Truhlář 2018-07-15 00:10:29

le code suivant produira un nombre aléatoire sécurisé entre 0 et 255:

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

Vous appelez ça comme ça:

print(UInt8.random)

pour un plus grand nombre il devient plus compliqué.

C'est le mieux que j'ai pu trouver:

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) { "151920920" << 8 + UInt16() }
  }
}

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) { "151920920" << 8 + UInt32() }
  }
}

ces méthodes utilisent un nombre aléatoire supplémentaire pour déterminer combien de UInt8 s vont être utilisés pour créer le nombre aléatoire. La dernière ligne convertit le [UInt8] en UInt16 ou UInt32 .

Je ne sais pas si les deux derniers comptent encore comme vraiment aléatoires, mais vous pouvez le modifier à votre image:)

2
répondu Zyphrax 2017-02-18 02:35:09

Swift 4.2

Swift 4.2 a inclus une API de nombres aléatoires native et assez complète dans la bibliothèque standard. ( Swift Évolution proposition SE-0202 )

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

tous les types de nombres ont la statique aléatoire (in:) qui prend la gamme et renvoie le nombre aléatoire dans la gamme donnée

2
répondu Suhit Patil 2018-06-10 18:29:59

détails

xCode 9.1, Swift 4

Mathématiques orientées vers la solution de (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
}

utilisation de la 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]

programmeurs oriented solution (2)

N'oubliez pas ajouter solution axée sur les mathématiques (1) code ici

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

utilisation de la 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]

Échantillon Complet

n'oubliez pas ajouter solution (1) et solution (2) codes ici

private func generateRandNums(closure:()->(Int)) {

    var allNums = Set<Int>()
    for _ in 0..<100 {
        allNums.insert(closure())
    }
    print(allNums.sorted{ "151940920" <  })
}

generateRandNums {
    (-8..<2).random
}

generateRandNums {
    (0..<10).random
}

generateRandNums {
    (-10 ... -2).random
}

generateRandNums {
    rand(-5, 5)
}
generateRandNums {
    rand[0, 10]
}

résultat de L'échantillon

enter image description here

1
répondu Vasily Bodnarchuk 2017-11-21 07:22:25

Swift 4.2

Bye bye à import Fondation 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()
  1. vous utilisez random(in:) pour générer des chiffres aléatoires à partir de fourchettes.
  2. randomElement () retourne nil si la plage est vide, donc vous déballez le retour Int? avec si de laisser.
  3. vous utilisez random(in:) pour générer un double aléatoire, Float ou CGFloat et random() pour retourner un Bool aléatoire.

Plus @ Officiel

1
répondu 27J91 2018-09-19 07:23:22

vous pouvez utiliser GeneratorOf comme ceci:

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())
0
répondu Durul Dalkanat 2015-06-18 23:24:29

j'utilise ce code pour générer un nombre aléatoire:

//
//  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]
    }
}
0
répondu Ahmadreza Shamimi 2016-06-12 03:38:48

pour iOS, macOS et tvOS vous pouvez utiliser system-wide random source dans le cadre de Xcode GameKit . Ici vous pouvez trouver GKRandomSource classe avec son sharedRandom() méthode de classe:

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

C'est écrit dans Swift 4.2.

0
répondu Gigantic 2018-06-08 07:55:08