Wie generiert man eine Zufallszahl in Apples Swift-Sprache?


443

Mir ist klar, dass das Swift-Buch eine Implementierung eines Zufallszahlengenerators enthielt. Ist es die beste Vorgehensweise, diese Implementierung zu kopieren und in das eigene Programm einzufügen? Oder gibt es eine Bibliothek, die dies jetzt tun kann?

Antworten:


466

Swift 4.2+

Swift 4.2, das mit Xcode 10 ausgeliefert wird, bietet neue benutzerfreundliche Zufallsfunktionen für viele Datentypen. Sie können die random()Methode für numerische Typen aufrufen .

let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()

7
Ich musste Darwin nicht explizit importieren
finneycanhelp

3
In meiner Playground-Datei musste ich Darwin importieren, weil ich nichts anderes importierte.
DonnaLea

SoliQuiD: außer den zusätzlichen Unterstrich nach arc4 weglassen, dh arc4random_uniform (5).
Ali Beadle

3
Warnung : Es wurde gezeigt , dass RC4 oder arc4 von reinen Zufallswerten unterscheidbar sind . Obwohl arc4 (eine Stream-Verschlüsselung) kryptografisch sicher klingt , ist dies tatsächlich nicht der Fall .
Maarten Bodewes

2
@ MaartenBodewes: Nicht mehr direkt relevant für diese Antwort, aber arc4random verwendet die RC4-Verschlüsselung trotz ihres Namens unter macOS oder den BSDs nicht. Es verwendet ein vom System bereitgestelltes CSPRNG unter macOS und ChaCha20 unter den meisten BSDs. Swifts Standard-RNG (wie in dieser Antwort verwendet) nennt es ein Implementierungsdetail unter macOS, verwendet jedoch auf jeder unterstützten Plattform einen geeigneten zugrunde liegenden Generator.
Stephen Canon

496

Verwenden Sie arc4random_uniform(n)für eine zufällige Ganzzahl zwischen 0 und n-1.

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

Wandeln Sie das Ergebnis in Int um, damit Sie Ihre Vars nicht explizit als eingeben müssen UInt32(was nicht schnell zu sein scheint).


7
Sehr einfach. Ich mag das. Upvote! Aber ein tatsächlicher Würfel hat nicht 0. In Ihrem Code diceRollkönnte sein 0. Ich sage nur ...
MK Safi

61
Ja, du willst wirklich Int(arc4random_uniform(6)+1).
Michael Dorst

5
Wahrscheinlichkeit = Int (arc4random_uniform (UInt32 (total))) - ich musste auch in UInt32
bshirley

4
let randomElementInArray = Int (arc4random_uniform (array.count))
cmario

Vergessen Sie nicht, den eingegebenen Parameter n in a umzuwandeln arc3random_uniform(n), UInt32(n)wenn Sie einen Wert verwenden, der noch nicht von diesem Typ ist.
Dave Fontenot

117

Bearbeiten: Aktualisiert für Swift 3.0

arc4randomfunktioniert gut in Swift, aber die Basisfunktionen sind auf 32-Bit-Integer-Typen beschränkt ( Int64-Bit auf iPhone 5S und modernen Macs). Hier ist eine generische Funktion für eine Zufallszahl eines Typs, der durch ein ganzzahliges Literal ausgedrückt werden kann:

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

Wir können diese neue generische Funktion verwenden, um zu erweitern UInt64, Grenzargumente hinzuzufügen und die Modulo-Verzerrung zu verringern. (Dies wird direkt von arc4random.c angehoben. )

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

Damit können wir Int64für die gleichen Argumente, die sich mit Überlauf befassen, erweitern:

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

Um die Familie zu vervollständigen ...

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

Nach all dem können wir endlich so etwas machen:

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

Es wird nicht kompiliert : var r = arc4random(UInt64). Bitte raten Sie, was Sie hier gemeint haben.
Ossir

@Ossir kompiliert gut für mich ... es bedeutet, die Funktion arc4random(definiert im ersten Codeblock) mit dem Argument aufzurufen, UInt64das a ist Type.
6.

Leiden arc4random_buf (und damit alle 64-Bit-Erweiterungen) unter Modulo Bias?
Matthew Seaman

Modulo Bias kommt nur ins Spiel, wenn Sie eine Obergrenze hinzufügen, daher gilt es nicht für arc4random_buf. Der Zweck dieser Erweiterungen besteht darin, genau das zu tun arc4random_uniform(Modulo Bias zu verringern), mit Ausnahme von 64-Bit-Typen.
14.

Wie kann ich bei Verwendung der Float-Funktionen den oberen Wert in den Bereich der Möglichkeiten aufnehmen? Nehmen wir also an, ich mache 0.0 als untere und 1.0 als obere. Mit dieser Logik gibt es mir 0.0 bis 0.99999999. Stattdessen möchte ich die 1.0 als Möglichkeit einbeziehen. Wie kann ich das erreichen?
MobileMon

80

Bearbeiten für Swift 4.2

Ab Swift 4.2 können Sie anstelle der importierten C-Funktion arc4random_uniform () jetzt die eigenen nativen Funktionen von Swift verwenden.

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

Sie können auch random(in:)Zufallswerte für andere primitive Werte abrufen. wie Int, Double, Float und sogar Bool.

Schnelle Versionen <4.2

Diese Methode generiert einen zufälligen IntWert zwischen dem angegebenen Minimum und Maximum

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

61

Ich habe diesen Code verwendet:

var k: Int = random() % 10;

20
Sie müssen zuerst srandom (UInt32 (time (nil))) aufrufen, sonst wird immer die gleiche Nummernfolge zurückgegeben
Hola Soy Edu Feliz Navidad

3
Ich habe das Apple-Dokument zweimal auf random () gelesen, konnte aber seine Verwendung nicht nachvollziehen ... Ich wünschte, sie hätten einfach ein einfaches Codebeispiel wie dieses oben aufgenommen. "Die Funktion random () verwendet einen nichtlinearen Zufallszahlengenerator mit additiver Rückkopplung, der eine Standardtabelle mit langen Ganzzahlen der Größe 31 verwendet. Sie gibt aufeinanderfolgende Pseudozufallszahlen im Bereich von 0 bis (2 31) -1 zurück Die Periode dieses Zufallszahlengenerators ist sehr groß, ungefähr 16 * ((2 31) -1). " ... Vielen Dank Apfel ... Ich werde dies in meiner nächsten Arbeit sicher erwähnen.
Nocarrier

1
random () führt manchmal zu einem plötzlichen Absturz auf iPads. Verwenden Sie in diesem Fall die Datei arc4random_uniform (6) von oben. Wenn Sie random () verwenden, können Sie mehr zufällige Werte erstellen, indem Sie srandomdev () voranstellen.
JackPearse

1
Ich habe eine Compiler-Fehlermeldung erhalten:random is unavailable in Swift: Use arc4random instead.
Mike Keskinov

1
Diese Lösung hat Modulo Bias: zuttobenkyou.wordpress.com/2012/10/18/…
rgov

33

Ab iOS 9 können Sie die neuen GameplayKit-Klassen verwenden, um Zufallszahlen auf verschiedene Arten zu generieren.

Sie haben vier Quelltypen zur Auswahl: eine allgemeine Zufallsquelle (unbenannt, bis auf das System, um auszuwählen, was sie tut), linear kongruent, ARC4 und Mersenne Twister. Diese können zufällige Ints, Floats und Bools erzeugen.

Auf der einfachsten Ebene können Sie eine Zufallszahl aus der integrierten Zufallsquelle des Systems wie folgt generieren:

GKRandomSource.sharedRandom().nextInt()

Das ergibt eine Zahl zwischen -2.147.483.648 und 2.147.483.647. Wenn Sie eine Zahl zwischen 0 und einer Obergrenze (exklusiv) möchten, verwenden Sie Folgendes:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit verfügt über einige praktische Konstruktoren, die für die Arbeit mit Würfeln integriert sind. Zum Beispiel können Sie einen sechsseitigen Würfel wie folgt würfeln:

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

Außerdem können Sie die Zufallsverteilung mithilfe von GKShuffledDistribution gestalten. Das braucht etwas mehr Erklärung, aber wenn Sie interessiert sind, können Sie mein Tutorial über GameplayKit-Zufallszahlen lesen .


1
Vielen Dank für diesen Tipp, es ist eine der besten Antworten. Um diese Funktionen nutzen zu können, muss man hinzufügen import GameplayKit. Swift 3 änderte die Syntax zuGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn

7
Wie schwer ist dieses Kit zu importieren? Ich möchte meinen Code nicht aufblähen.
μολὼν.λαβέ

25

Sie können es genauso machen wie in C:

let randomNumber = arc4random()

randomNumberEs wird davon ausgegangen, dass es sich um einen Typ handelt UInt32(eine vorzeichenlose 32-Bit-Ganzzahl).


12
Nachtrag: rand, arc4random, drand48und Freunde sind alle in dem DarwinModul. Es ist bereits für Sie importiert, wenn Sie eine Kakao-, UIKit- oder Foundation-App erstellen, aber Sie müssen es import Darwinauf Spielplätzen tun .
Rickster

5
Versuchen Sie nicht, das Ergebnis von arc4random () in ein Int umzuwandeln. Dies funktioniert auf einer 64-Bit-Plattform einwandfrei. Auf einer 32-Bit-Plattform sind Ints jedoch 32-Bit-signiert, sodass Sie unerwartet negativ werden Zahlen. Das hat schon ein paar Leute gestolpert, also dachte ich mir, ich würde es hier erwähnen.
Matt Gibson

23

Verwenden arc4random_uniform()

Verwendungszweck:

arc4random_uniform(someNumber: UInt32) -> UInt32

Dies gibt Ihnen zufällige ganze Zahlen im Bereich 0bis someNumber - 1.

Der Maximalwert für UInt32beträgt 4.294.967.295 (dh 2^32 - 1).

Beispiele:

  • Münzwurf

    let flip = arc4random_uniform(2) // 0 or 1
  • Würfelwurf

    let roll = arc4random_uniform(6) + 1 // 1...6
  • Zufälliger Tag im Oktober

    let day = arc4random_uniform(31) + 1 // 1...31
  • Zufälliges Jahr in den 1990er Jahren

    let year = 1990 + arc4random_uniform(10)

Generelle Form:

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

wo number, maxund minsind UInt32.

Wie wäre es mit...

arc4random ()

Sie können auch eine Zufallszahl erhalten, indem Sie arc4random()eine UInt32zwischen 0 und 2 ^ 32-1 erzeugen . Um eine Zufallszahl zwischen 0und zu erhalten x-1, können Sie sie durch dividieren xund den Rest nehmen. Oder verwenden Sie mit anderen Worten den Restoperator (%) :

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

Dies erzeugt jedoch eine leichte Modulo-Vorspannung (siehe auch hier und hier ), weshalb arc4random_uniform()empfohlen wird.

Konvertieren von und nach Int

Normalerweise wäre es in Ordnung, so etwas zu tun, um zwischen Intund hin und her zu konvertieren UInt32:

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

Das Problem ist jedoch, dass Intes eine Reichweite von -2,147,483,648...2,147,483,64732-Bit-Systemen und eine Reichweite von -9,223,372,036,854,775,808...9,223,372,036,854,775,80764-Bit-Systemen gibt. Vergleichen Sie dies mit dem UInt32Bereich von 0...4,294,967,295. Das Uvon UInt32bedeutet unsigniert .

Beachten Sie die folgenden Fehler:

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

Sie müssen also nur sicherstellen, dass Ihre Eingabeparameter innerhalb des UInt32Bereichs liegen und dass Sie auch keine Ausgabe benötigen, die außerhalb dieses Bereichs liegt.


19

Beispiel für eine Zufallszahl zwischen 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Sehr einfacher Code - einfach und kurz.


16

Ich konnte nur verwenden rand(), um ein zufälliges CInt zu erhalten. Sie können daraus ein Int machen, indem Sie Folgendes verwenden:

let myVar: Int = Int(rand())

Sie können Ihre bevorzugte C-Zufallsfunktion verwenden und bei Bedarf einfach in den Wert in Int konvertieren.


Ja, die Typkonvertierung kann ansonsten ein heikles Geschäft sein, und es ist wirklich schmerzhaft, den Int-Konstruktor damit umgehen zu lassen.
Kzrbill

4
Beachten Sie, dass die Reihenfolge der Zahlen zwischen jeder Ausführung Ihres Programms immer exakt gleich ist, wenn Sie srand (...) nicht aufrufen (nur einmal aufrufen), bevor Sie rand () verwenden. Wenn Sie dies nicht möchten, verwenden Sie arc4random ()
SomeGuy

2
Sie können auch verwenden random(), was ein Inteher als zurückgibt UInt32- und wie @SomeGuy erwähnt, einfach srandom(arc4random())einmal irgendwo aufrufen , bevor Sie es verwenden, um sicherzustellen, dass es für jede Ausführung Ihres Programms einen anderen, zufälligen Startwert hat.
brittlewis12

1
Kann jemand einen Kommentar zu rand () vs arc4random_uniform () abgeben?
Ruben Martinez Jr.

16

@ jstns Antwort ist gut, aber etwas ausführlich. Swift ist als protokollorientierte Sprache bekannt, sodass wir das gleiche Ergebnis erzielen können, ohne für jede Klasse in der Integer-Familie Boilerplate-Code implementieren zu müssen, indem wir eine Standardimplementierung für die Protokollerweiterung hinzufügen.

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

Jetzt können wir tun:

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

und alle anderen ganzzahligen Klassen sind in Ordnung.


11

In Swift 4.2 können Sie Zufallszahlen generieren, indem Sie die random()Methode für einen beliebigen numerischen Typ aufrufen und den Bereich angeben, mit dem Sie arbeiten möchten. Dies erzeugt beispielsweise eine Zufallszahl im Bereich von 1 bis 9, einschließlich auf beiden Seiten

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

Auch bei anderen Typen

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

9

Hier ist eine Bibliothek, die ihre Arbeit gut macht 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
    }
}

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

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

6

Ich möchte zu den vorhandenen Antworten hinzufügen, dass das Beispiel des Zufallszahlengenerators im Swift-Buch ein linearer Kongruenzgenerator (Linear Congruence Generator, LCG) ist. Es ist stark eingeschränkt und sollte nur die trivialen Beispiele sein, bei denen die Qualität der Zufälligkeit dies nicht tut ist überhaupt nicht wichtig. Und ein LCG sollte niemals für kryptografische Zwecke verwendet werden .

arc4random()ist viel besser und kann für die meisten Zwecke verwendet werden, sollte aber auch hier nicht für kryptografische Zwecke verwendet werden.

Wenn Sie etwas wünschen, das garantiert kryptografisch sicher ist, verwenden Sie SecCopyRandomBytes(). Beachten Sie, dass, wenn Sie einen Zufallszahlengenerator in etwas einbauen, jemand anderes ihn möglicherweise (falsch) für kryptografische Zwecke (wie Kennwort-, Schlüssel- oder Salzgenerierung) verwendet. Sie sollten die Verwendung SecCopyRandomBytes()trotzdem in Betracht ziehen , auch wenn dies nicht erforderlich ist. Ich brauche das nicht ganz.


6

Seit Swift 4.2

Es gibt eine neue Reihe von APIs:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Alle numerischen Typen haben jetzt die random(in:)Methode, die akzeptiert wird range.

  • Es wird eine gleichmäßig in diesem Bereich verteilte Zahl zurückgegeben.


TL; DR

Nun, was ist los mit dem "guten" alten Weg?

  1. Sie müssen importierte C- APIs verwenden (diese unterscheiden sich zwischen den Plattformen) .

  2. Und außerdem ...

Was wäre, wenn ich dir sagen würde, dass der Zufall nicht so zufällig ist?

Wenn Sie arc4random() (um den Rest zu berechnen) wie verwenden arc4random() % aNumber, wird das Ergebnis nicht gleichmäßig zwischen 0und verteilt aNumber. Es gibt ein Problem, das als Modulo-Bias bezeichnet wird .

Modulo Bias

Normalerweise generiert die Funktion eine Zufallszahl zwischen 0und MAX (abhängig vom Typ usw.) . Um ein schnelles und einfaches Beispiel zu erstellen, nehmen wir an, die maximale Anzahl ist 7und Sie interessieren sich für eine Zufallszahl im Bereich 0 ..< 2 (oder im Intervall [0, 3), wenn Sie dies bevorzugen) .

Die Wahrscheinlichkeiten für einzelne Zahlen sind:

  • 0: 3/8 = 37,5%
  • 1: 3/8 = 37,5%
  • 2: 2/8 = 25%

Mit anderen Worten : Sie sind eher am Ende mit 0 oder 1 als 2 . Bedenken Sie natürlich, dass dies extrem vereinfacht ist und die MAX- Zahl viel höher ist, was es "fairer" macht.

Dieses Problem wird durch SE-0202 - Zufällige Vereinheitlichung in Swift 4.2 behoben


5

Ohne arc4Random_uniform () in einigen Versionen von Xcode (in 7.1 wird es ausgeführt, aber für mich nicht automatisch vervollständigt). Sie können dies stattdessen tun.

So generieren Sie eine Zufallszahl von 0-5. Zuerst

import GameplayKit

Dann

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

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

Hier wird 5 sicherstellen, dass die Zufallszahl durch null bis vier erzeugt wird. Sie können den Wert entsprechend einstellen.


1
Wenn Sie 5 bestehen, werden 5 mögliche Ergebnisse von null bis vier zurückgegeben. 0 ... 4
Leo Dabus

3

Swift 4.2

Tschüss, um Foundation C lib zu importieren 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. Sie verwenden random (in :), um zufällige Ziffern aus Bereichen zu generieren.
  2. randomElement () gibt nil zurück, wenn der Bereich leer ist. Sie packen also das zurückgegebene Int? mit wenn lassen.
  3. Sie verwenden random (in :), um ein zufälliges Double, Float oder CGFloat zu generieren, und random (), um ein zufälliges Bool zurückzugeben.

Mehr @ Offiziell


2

Der folgende Code erzeugt eine sichere Zufallszahl zwischen 0 und 255:

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

Sie nennen es so:

print(UInt8.random)

Bei größeren Zahlen wird es komplizierter.
Dies ist das Beste, was ich mir vorstellen kann:

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

Diese Methoden verwenden eine zusätzliche Zufallszahl, um zu bestimmen, wie viele UInt8s zum Erstellen der Zufallszahl verwendet werden sollen. Die letzte Zeile konvertiert das [UInt8]nach UInt16oder UInt32.

Ich weiß nicht, ob die letzten beiden immer noch als wirklich zufällig gelten, aber Sie können es nach Ihren Wünschen anpassen :)


Sie haben die durch Modulo eingeführte Verzerrung +1 geschickt vermieden. Sie könnten die Leser warnen, warum Sie es getan haben.
JWW

Das ist interessant, ich habe nicht wirklich gedacht, dass hier Modulo-Voreingenommenheit im Spiel sein könnte. Vielleicht sind die Chancen, eine kleine Zahl zu bekommen, nicht die gleichen wie eine große Zahl.
Zyphrax

2

Swift 4.2

Swift 4.2 hat eine native und ziemlich voll funktionsfähige Zufallszahlen-API in die Standardbibliothek aufgenommen. ( Swift Evolution Vorschlag SE-0202 )

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

Alle Zahlentypen haben den statischen Zufall (in :), der den Bereich übernimmt und die Zufallszahl im angegebenen Bereich zurückgibt


1

Swift 4.2, Xcode 10.1 .

Für iOS, macOS und tvOS können Sie im Xcode-Framework systemweite Zufallsquellen verwenden GameKit. Hier finden Sie die GKRandomSourceKlasse mit ihrer sharedRandom()Klassenmethode:

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]
}
randomGenerator()

Oder verwenden Sie einfach eine randomElement()Methode, die ein zufälliges Element der Sammlung zurückgibt:

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

let randomNumber = number.randomElement()!
print(randomNumber)

0

Sie können GeneratorOfwie folgt verwenden:

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

3
Wie ist Fibonacci zufällig?
Nikolai Ruhe

Hallo Nikolai, dieser Codeblock ist eine alte Version von Swift 1.2. Wenn Sie das neue Swift 2.0 ausprobieren. Es wäre keine Arbeit.
Durul Dalkanat

2
Ich verstehe, aber es sieht für mich immer noch wie ein Fibonacci-Generator aus, nicht wie Zufallszahlen, wie in der Frage gefordert.
Nikolai Ruhe

0

Ich benutze diesen Code, um eine Zufallszahl zu generieren:

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

2
Willkommen bei SO. Von Antworten nur auf Code wird abgeraten. Bitte bearbeiten Sie Ihre Antwort, um zu erklären, warum dieser Code die Frage beantwortet und wie er funktioniert. Weitere Informationen finden Sie unter stackoverflow.com/help/how-to-answer.
Tim Malone

2
Bitte geben Sie einen Kontext für Ihre Antwort an und begrüßen Sie den Stapelüberlauf. :)
Jonathan Eustace

0

Einzelheiten

xCode 9.1, Swift 4

Mathematikorientierte Lösung (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
}

Verwendung der Lösung (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]

Programmiererorientierte Lösung (2)

Vergessen Sie nicht, Math orientierte Lösung (1) Code hinzufügen hier

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

Verwendung der Lösung (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]

Vollständige Probe

Vergessen Sie nicht, hier die Codes für Lösung (1) und Lösung (2) hinzuzufügen

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

Beispielergebnis

Geben Sie hier die Bildbeschreibung ein


2
Diese Antwort ist nicht zum Thema. Die Frage war, wie man eine Zufallszahl generiert. Nicht, wie man eine Zufallszahlenbibliothek erstellt. Meine Güte.
Andrew Paul Simmons
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.