Wie macht man eine Zufallszahl zwischen dem Bereich für arc4random_uniform ()?


129

Mein Ziel in diesem Codebit ist es also, zufällig zwei Würfel zu würfeln. Wie wir alle wissen, hat Ihr regulärer Würfel nur 6 Seiten. Deshalb habe ich Foundation für den Zugriff auf arc4random_uniform (UInt32) importiert. Ich habe versucht, den Bereich von (1..7) zu verwenden, um zu vermeiden, dass zufällig 0 angezeigt wird. Dies hat jedoch einen Fehler zurückgegeben, den ich nicht besonders genossen habe. Ich habe versucht, dies zu tun:

dice1 = arc4random_uniform(UInt32(1..7))

das kehrte jedoch zurück

Es wurde keine Überladung für 'init' gefunden, die die angegebenen Argumente akzeptiert

Ich hoffe, dass dies genug Informationen für Sie sind, um mir zu helfen :)

Bitte beachten Sie, dass ich dies nur auf einem Spielplatz mache, um schnell zu üben. Ich muss nicht unbedingt lernen, wie man das macht. Ich bastele nur, bevor ich mit dem Erstellen tatsächlicher Apps beginne: D.

//imports random number function
import Foundation
//creates data storage for dice roll
var dice1: UInt32 = 0
var dice2: UInt32 = 0
//counter variable
var i = 0
//how many times snake eyes happens
var snakeeyes = 0
 //how many times a double is rolled
var `double` = 0
//rolls dice 100 times
while i < 100{
    //from here
    //sets dice roll

Dies gibt den Fehler zurück, dass 'Range $ T3' nicht in UInt32 konvertierbar ist

   dice1 = arc4random_uniform(1..7)
   dice2 = arc4random_uniform(1..7)
    //checks for snake eyes
    if dice1 == 1 && dice2 == 1 {
        snakeeyes = snakeeyes + 1

    }
    //checks for doubles
    if dice1 == dice2{
        `double` = `double` + 1
    }
    //increases counter
        i = i + 1
    //to here
}
println("You got Snake Eyes \(snakeeyes) times.")
println("You got Doubles, \(`double`) times.")

4
Ich glaube, Sie sollten etwas tun dice1 = arc4random_uniform(6) + 1, um den Bereich 1 - 6 zu erreichen. Ich mache weder iOS-Ziel C noch habe ich Kenntnisse über schnelle Sprache. Die Zufallsmethode sollte 0 - 5 zurückgeben, und + 1 ist 1 - 6.
Sky

1
Bereich ist ein Objekt Daten selbst, es ist keine Ganzzahl Daten, deshalb erhalten Sie den Fehler, wenn das Argument nur (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

Aha! Danke Himmel! Ich habe eine Zusicherung gemacht, um zu testen, ob sie unter 0 liegt, und kann bestätigen, dass dies genau das war, was ich brauchte. Geben Sie sie als Antwort ein, damit ich sie als solche abhaken kann!
arcreigh

Wahrscheinlichkeit = Int (arc4random_uniform (UInt32 (total))) - wenn Sie mehrere Casting-Beschwerden haben, die nicht spezifisch sind (weil die Typeahead / Header nicht funktionieren)
bshirley

Dies ist ab Swift 4.2 eingebaut, wie unten gezeigt. Stackoverflow.com/a/50696901/1148030
Peter Lamberg

Antworten:


260

Ich glaube du solltest es tun

dice1 = arc4random_uniform(6) + 1;

um den Bereich 1 - 6 zu erreichen. Ich mache weder iOS-Ziel C noch habe ich irgendwelche Kenntnisse in der schnellen Sprache. Die Zufallsmethode sollte einen Wert zwischen 0 und 5 zurückgeben, und + 1 ergibt einen Wert zwischen 1 und 6.

Wenn Sie einen Bereich zwischen 10 und 30 benötigen, tun Sie dies einfach

int random = arc4random_uniform(21) + 10;

2
@JoeSmith Sie sind genau richtig, es sollte arc4random_uniform (21) +10 sein, um einen Bereich zwischen 10 - 30 zurückzugeben, da die Obergrenze nicht inklusive ist. Der Teil "arc4random_uniform (20) +10" basiert auf Community-Bearbeitung und Abstimmungen.
Sky

Ja, ich habe gerade getestet und um eine zufällige Farbe zu erhalten (dh einen zufälligen Wert zwischen und einschließlich 0 - 255 zu wollen), habe ich verwendet: "arc4random_uniform (256) + 0"
Chris Allinson

91

Ich habe eine Erweiterung vom Typ Int erstellt. Ich habe es auf dem Spielplatz getestet und hoffe, dass dies nützlich ist. Es werden auch negative Bereiche akzeptiert:

extension Int
{
    static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.startIndex < 0   // allow negative ranges
        {
            offset = abs(range.startIndex)
        }

        let mini = UInt32(range.startIndex + offset)
        let maxi = UInt32(range.endIndex   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

benutze wie

var aRandomInt = Int.random(-500...100)  // returns a random number within the given range.

oder definieren Sie es als Range-Erweiterung als Eigenschaft wie folgt:

extension Range
{
    var randomInt: Int
    {
        get
        {
            var offset = 0

            if (startIndex as Int) < 0   // allow negative ranges
            {
                offset = abs(startIndex as Int)
            }

            let mini = UInt32(startIndex as Int + offset)
            let maxi = UInt32(endIndex   as Int + offset)

            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

// usage example: get an Int within the given Range:
let nr = (-1000 ... 1100).randomInt

6
Ihre Erweiterung ist wunderschön: 3 Eine echte Verwendung von Swift!
Kalzem

Ich mag die Range-Erweiterung.
David James

Gute Antwort. Meine einzige Einschränkung wäre zu sagen, dass randomInt: keine natürliche Erweiterung von Int oder Range ist. Ich würde dies einfach als eigenständige Funktion in eine Dienstprogrammdatei einfügen.
Vince O'Sullivan

Muss für Swift 3 aktualisiert werden, ersetzen Sie stattdessen range.startIndex durch range.lowerBound und endIndex ist jetzt UpperBound
Joseph

62

Einige gute Antworten, aber ich wollte nur meine persönliche Lieblingsfunktion zur Erzeugung von Swift-Zufallszahlen für positive ganze Zahlen teilen:

Swift 2

func randomNumber(range: Range<Int> = 1...6) -> Int {
    let min = range.startIndex
    let max = range.endIndex
    return Int(arc4random_uniform(UInt32(max - min))) + min
}

Swift 3

Hier ist ein schnelles Update für Swift 3, und als Bonus funktioniert es jetzt für jeden Werttyp, der dem SignedInteger-Protokoll entspricht - viel praktischer für Kerndatenanwendungen, in denen Int16, Int32 usw. angegeben werden müssen Ich brauche es wirklich, um auch mit vorzeichenlosen Ganzzahlen zu arbeiten. Kopieren Sie einfach die gesamte Funktion und ersetzen Sie sie SignedIntegerdurch UnsignedIntegerund toIntMax()mit toUIntMax().

func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = (range.upperBound - range.lowerBound + 1).toIntMax()
    let value = arc4random().toIntMax() % length + range.lowerBound.toIntMax()
    return T(value)
}

Swift 4

Dank der Entfernung von toIntMax () in Swift 4 müssen wir jetzt ein anderes Mittel zum Konvertieren in einen gemeinsamen Integer-Typ verwenden. In diesem Beispiel verwende ich Int64, das für meine Zwecke groß genug ist. Wenn Sie jedoch vorzeichenlose Ganzzahlen verwenden oder einen benutzerdefinierten Int128- oder Int256-Typ haben, sollten Sie diese verwenden.

public func randomNumber<T : SignedInteger>(inRange range: ClosedRange<T> = 1...6) -> T {
    let length = Int64(range.upperBound - range.lowerBound + 1)
    let value = Int64(arc4random()) % length + Int64(range.lowerBound)
    return T(value)
}

Eine weitere Erweiterung für das gesamte Zufallsphil ist eine Erweiterung, die ein zufälliges Element von einem beliebigen CollectionObjekt zurückgibt . Beachten Sie, dass dies die obige Funktion verwendet, um den Index zu generieren, sodass Sie beide benötigen.

extension Collection {
    func randomItem() -> Self.Iterator.Element {
        let count = distance(from: startIndex, to: endIndex)
        let roll = randomNumber(inRange: 0...count-1)
        return self[index(startIndex, offsetBy: roll)]
    }
}

Verwendung

randomNumber()

gibt eine Zufallszahl zwischen 1 und 6 zurück.

randomNumber(50...100)

Gibt eine Zahl zwischen 50 und 100 einschließlich zurück. Natürlich können Sie die Werte 50 und 100 durch beliebige Werte ersetzen.

Swift 4.2

Leider ist meine beste StackOverflow-Antwort endlich veraltet. Sie können jetzt einfach Int.random(in: 1 ... 6)eine Zufallszahl in einem bestimmten Bereich generieren. Funktioniert auch für andere Formen von Ganzzahlen und Gleitkommazahlen. Collection - Typen auch jetzt bieten shuffle()und randomElement()Funktionen. Es sind daher keine ausgefallenen Randomisierungsfunktionen mehr erforderlich, es sei denn, Sie möchten einen bestimmten Randomisierertyp verwenden.


1
Ich habe mir das angeschaut und dachte, es muss falsch sein, weil (max - min) = 5, was eine zufällige ganze Zahl im Bereich von 0 bis 4 ergibt (plus 1 ergibt 1 bis 5). Aber durch das Einfügen des Codes in einen Xcode-Spielplatz wurde deutlich, dass es funktionierte. Der Grund dafür ist, dass max tatsächlich gleich 7 ist, da endIndex "Die erste Position der Sammlung nach dem Ende" zurückgibt. (wie in der Apple-Dokumentation angegeben). Also eine gute Antwort und eine nützliche Lernübung für mich.
Vince O'Sullivan

Dies funktioniert auch mit negativen ganzen Zahlen. randomNumber(-3 ... -1)funktioniert so lange, wie Sie Leerzeichen vor und nach dem haben .... Sie können auch random(-3 ..< -1die letzte Nummer ausschließen.
Carter Medlin

Verwenden Sie ClosedIntervalanstelle von, Rangewenn Sie möchten, dass dies mit Nicht-Ganzzahlen funktioniert.
Carter Medlin

Ich würde nicht. Intervalltypen waren in Swift 3 veraltet. Es gibt wahrscheinlich eine Möglichkeit, Generics zu verwenden, um die Funktionalität des Codes zu erweitern, aber ich hatte weder Zeit noch Neigung oder Grund, dies zu untersuchen.
Ash

1
Los geht's, eine generische Ganzzahlversion des Codes.
Ash


18

Wenn du willst, erstelle ich das für Zufallszahlen. Dies ist die Erweiterung der Nummern Int und Double, Float

/**
    Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, UInt(sizeof(T)))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (#lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(upper - lower + 1))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(#lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(#lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

VERWENDEN :

let randomNumDouble = Double.random(lower: 0.00, upper: 23.50)
let randomNumInt = Int.random(lower: 56, upper: 992)
let randomNumInt =Float.random(lower: 6.98, upper: 923.09)

binärer Operator / kann nicht auf zwei Doppeloperanden angewendet werden
Jason G

13

Swift 3/4:

func randomNumber(range: ClosedRange<Int> = 1...6) -> Int {
    let min = range.lowerBound
    let max = range.upperBound
    return Int(arc4random_uniform(UInt32(1 + max - min))) + min
}

8

Das liegt daran, dass arc4random_uniform () wie folgt definiert ist:

func arc4random_uniform(_: UInt32) -> UInt32

Es nimmt ein UInt32 als Eingabe und spuckt ein UInt32 aus. Sie versuchen, einen Wertebereich zu übergeben. arc4random_uniform gibt Ihnen eine Zufallszahl zwischen 0 und der Zahl, die Sie (ausschließlich) übergeben. Wenn Sie also beispielsweise eine Zufallszahl zwischen -50 und 50 suchen möchten, wie [-50, 50]Sie sie verwenden könntenarc4random_uniform(101) - 50


Sky hat meine Frage perfekt beantwortet. Ich glaube, Sie sagen dasselbe. Vielen Dank. Sie können bestätigen, dass durch Setzen von dice1,2 = arc4random_uniform (6) +1 der Bereich tatsächlich auf 1-6 gesetzt wurde. Ich habe dies mit einer Behauptung getestet: D
arcreigh

6

Ich habe die Antwort von @DaRk -_- D0G geändert, um mit Swift 2.0 zu arbeiten

/**
Arc Random for Double and Float
*/
public func arc4random <T: IntegerLiteralConvertible> (type: T.Type) -> T {
    var r: T = 0
    arc4random_buf(&r, sizeof(T))
    return r
}
public extension Int {
    /**
    Create a random num Int
    :param: lower number Int
    :param: upper number Int
    :return: random number Int
    By DaRkDOG
    */
    public static func random (lower: Int , upper: Int) -> Int {
        return lower + Int(arc4random_uniform(UInt32(upper - lower + 1)))
    }

}
public extension Double {
    /**
    Create a random num Double
    :param: lower number Double
    :param: upper number Double
    :return: random number Double
    By DaRkDOG
    */
    public static func random(lower: Double, upper: Double) -> Double {
        let r = Double(arc4random(UInt64)) / Double(UInt64.max)
        return (r * (upper - lower)) + lower
    }
}
public extension Float {
    /**
    Create a random num Float
    :param: lower number Float
    :param: upper number Float
    :return: random number Float
    By DaRkDOG
    */
    public static func random(lower: Float, upper: Float) -> Float {
        let r = Float(arc4random(UInt32)) / Float(UInt32.max)
        return (r * (upper - lower)) + lower
    }
}

Schnellste Lösung hier! Vielen Dank!
Andrew


3

In kurzer Zeit ...

Dies ist inklusive, ein Anruf random(1,2)gibt eine 1 oder eine 2 zurück. Dies funktioniert auch mit negativen Zahlen.

    func random(min: Int, _ max: Int) -> Int {
        guard min < max else {return min}
        return Int(arc4random_uniform(UInt32(1 + max - min))) + min
    }

3

Die Antwort ist nur 1 Zeilencode:

let randomNumber = arc4random_uniform(8999) + 1000 //for 4 digit random number
let randomNumber = arc4random_uniform(899999999) + 100000000 //for 9 digit random number
let randomNumber = arc4random_uniform(89) + 10    //for 2 digit random number
let randomNumber = arc4random_uniform(899) + 100  //for 3 digit random number

Die alternative Lösung ist:

    func generateRandomNumber(numDigits: Int) -> Int{
    var place = 1
    var finalNumber = 0;
    var finanum = 0;
    for var i in 0 ..< numDigits {
        place *= 10
        let randomNumber = arc4random_uniform(10)         
        finalNumber += Int(randomNumber) * place
        finanum = finalNumber / 10
           i += 1
    }
    return finanum
}

Obwohl der Nachteil ist, dass diese Zahl nicht bei 0 beginnen kann.


2

Seit Swift 4.2:

Int {    
    public static func random(in range: ClosedRange<Int>) -> Int
    public static func random(in range: Range<Int>) -> Int
}

Verwendet wie:

Int.random(in: 2...10)

2

Edit: Swift 4.2+ bietet dies jetzt:

(100...200).randomElement()

Es ist für mich idiomatisch zu erweitern Range:

public extension Range where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound)))
    }
}

public extension ClosedRange where Bound == Int {
    var random: Int {
        return lowerBound + Int(arc4random_uniform(UInt32(upperBound - lowerBound + 1)))
    }
}

In Benutzung:

let foo = (100..<600).random

Wahrscheinlich nur eine stilistische Sache. Beide Methoden haben keinen inhärenten Vorteil, sondern nur das, womit Sie sich wohler fühlen.
Ash

1
Für Leute, die diesen „Stil“ betrachten, habe ich eine Sprachempfehlung für sie : C. Habe Spaß!
mxcl

Ich bin sicher, jemand hatte es bereits vor 3 Jahren getan :) stackoverflow.com/questions/34712453/…
Leo Dabus

1

Ich habe erfolgreich eine Zufallszahl mit dem folgenden Code erstellt:

var coin = arc4random_uniform(2) + 1

Hoffe das kann dir helfen.


0

Swift 3 Xcode Beta 5 Lösung. Basierend auf Ted van Gaalen Antwort.

extension Int
  {
     static func random(range: Range<Int> ) -> Int
    {
        var offset = 0

        if range.lowerBound < 0   // allow negative ranges
        {
            offset = Swift.abs(range.lowerBound)
        }

        let mini = UInt32(range.lowerBound + offset)
        let maxi = UInt32(range.upperBound   + offset)

        return Int(mini + arc4random_uniform(maxi - mini)) - offset
    }
}

0

var rangeFromLimits = arc4random_uniform ((UPPerBound - LOWerBound) + 1)) + LOWerBound;


0

hoffe das funktioniert. Zufallszahl zwischen Bereich für arc4random_uniform () machen?

var randomNumber = Int(arc4random_uniform(6))
print(randomNumber)

0

Wahrscheinlich findet man diese etwas aktualisierte Version der RangeErweiterung aus Ted van Gaalens Antwort mit Swift 4 / Xcode 9+ nützlich :

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        get {
            var offset = 0
            if lowerBound < 0 {
                offset = abs(lowerBound)
            }
            let mini = UInt32(lowerBound + offset)
            let maxi = UInt32(upperBound + offset)
            return Int(mini + arc4random_uniform(maxi - mini)) - offset
        }
    }
}

let n = (-1000 ... 1000).randomFromRange
print(n)

Oder diese etwas "hackige" Lösung zur Unterstützung offener und geschlossener Intervalle:

extension CountableRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound)
    }
}

extension CountableClosedRange where Bound == Int {
    var randomFromRange: Bound {
        return uniformRandom(from: lowerBound, to: upperBound - 1)
    }
}

func uniformRandom(from: Int, to: Int) -> Int {
    var offset = 0
    if from < 0 {
        offset = abs(from)
    }
    let mini = UInt32(from + offset)
    let maxi = UInt32(to + offset)
    return Int(mini + arc4random_uniform(maxi - mini)) - offset
}

Ich bin mir nicht sicher, ob es eine Möglichkeit gibt, beiden Intervalltypen gleichzeitig Eigenschaften hinzuzufügen.

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.