Come si fa a fare un numero casuale tra intervallo per arc4random_uniform ()?


129

quindi il mio obiettivo in questo codebit è di tirare casualmente due dadi e, come tutti sappiamo, il tuo dado normale ha solo 6 facce, quindi ho importato Foundation per l'accesso a arc4random_uniform (UInt32). Ho tentato di utilizzare l'intervallo di (1..7) per evitare di ottenere casualmente 0 ma ciò ha restituito un errore che non mi è piaciuto troppo. Ho provato a fare questo:

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

tuttavia quello è tornato

Impossibile trovare un sovraccarico per "init" che accetta gli argomenti forniti

Spero che queste siano informazioni sufficienti per voi fantastici debs là fuori per aiutarmi :)

Si prega di notare che sto solo facendo questo in un parco giochi per esercitarmi rapidamente. Non è indispensabile che impari a farlo; sono solo io a armeggiare prima di iniziare a creare app reali: 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

Ciò restituisce un errore di "Range $ T3" non convertibile in UInt32

   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
Credo che dovresti fare dice1 = arc4random_uniform(6) + 1per ottenere l'intervallo 1 - 6. Non faccio iOS C obiettivo, né ho alcuna conoscenza del linguaggio veloce. Il metodo casuale dovrebbe restituirti 0 - 5 e + 1 sarà 1 - 6.
Sky

1
L'intervallo è un dato oggetto stesso, non è un numero intero, ecco perché stai ricevendo l'errore quando l'argomento accetta solo (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

aha! grazie cielo! ha fatto un'affermazione per testare se stava andando a meno di 0 e posso confermare che era esattamente quello di cui avevo bisogno mettilo come una risposta in modo da poterlo controllare in quanto tale!
Arcreigh,

probabilità = Int (arc4random_uniform (UInt32 (totale))) - se hai più lamentele di casting non specifiche (perché i caratteri tipografici / le intestazioni non sono funzionali)
bshirley

Questo è costruito a partire da Swift 4.2 come indicato di seguito su stackoverflow.com/a/50696901/1148030
Peter Lamberg

Risposte:


260

Credo che dovresti farlo

dice1 = arc4random_uniform(6) + 1;

per ottenere l'intervallo 1 - 6. Non faccio iOS C obiettivo né ho alcuna conoscenza del linguaggio rapido però. Il metodo casuale dovrebbe restituire un valore compreso tra 0 e 5 e + 1 lo renderà un valore compreso tra 1 e 6.

Se hai bisogno di un intervallo tra diciamo 10 - 30, allora fallo

int random = arc4random_uniform(21) + 10;

2
@JoeSmith hai esattamente ragione su questo, dovrebbe essere arc4random_uniform (21) +10 per restituire un intervallo tra 10 - 30 poiché il limite superiore non è inclusivo. La parte "arc4random_uniform (20) +10" si basa sulla modifica e sui voti della community.
Sky

Sì, ho appena testato e per ottenere un colore casuale (cioè volendo un valore casuale compreso e compreso tra 0 e 255), ho usato: "arc4random_uniform (256) + 0"
Chris Allinson,

91

Ho creato un'estensione di tipo Int. testato nel parco giochi, spero che sia utile. Accetta anche intervalli negativi:

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

usa come

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

o definiscilo come estensione Range come proprietà come questa:

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
La tua estensione è bellissima: 3 Un vero utilizzo di Swift!
Kalzem,

Mi piace l'estensione Range.
David James,

Buona risposta. La mia unica avvertenza sarebbe quella di dire che randomInt: non è un'estensione naturale di Int o Range. Vorrei semplicemente aggiungere questo come una funzione autonoma in un file di utilità.
Vince O'Sullivan,

Deve essere aggiornato per swift 3, sostituisci range.startIndex con range.lowerBound invece e endIndex è ora upperBound
Joseph Astrahan

62

Molte buone risposte, ma volevo solo condividere la mia funzione di generazione di numeri casuali Swift preferita personale per numeri interi positivi:

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

Ecco un rapido aggiornamento per Swift 3 e, come bonus, ora funziona per qualsiasi tipo di valore conforme al protocollo SignedInteger - molto più conveniente per le applicazioni di dati core che devono specificare Int16, Int32 ecc. Come nota veloce, se si serve davvero che funzioni anche su numeri interi senza segno, basta copiare l'intera funzione e sostituirla SignedIntegercon UnsignedIntegere toIntMax()con 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

Grazie alla rimozione di toIntMax () in Swift 4, ora dobbiamo usare un mezzo diverso di conversione in un tipo intero comune. In questo esempio sto usando Int64 che è abbastanza grande per i miei scopi, ma se stai usando numeri interi senza segno o hai un tipo personalizzato Int128 o Int256, dovresti usarli.

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

Ancora una volta, per il totale file casuale, ecco un'estensione che restituisce un elemento casuale da qualsiasi Collectionoggetto di tipo. Nota che utilizza la funzione sopra per generare il suo indice, quindi avrai bisogno di entrambi.

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

uso

randomNumber()

restituisce un numero casuale compreso tra 1 e 6.

randomNumber(50...100)

restituisce un numero compreso tra 50 e 100 inclusi. Naturalmente puoi sostituire i valori di 50 e 100 con quello che preferisci.

Rapido 4.2

Purtroppo, la mia migliore risposta StackOverflow è stata finalmente resa obsoleta. Ora puoi usare semplicemente Int.random(in: 1 ... 6)per generare un numero casuale in un determinato intervallo. Funziona anche con altre forme di numero intero e in virgola mobile. Anche i tipi di raccolta ora forniscono shuffle()e randomElement()funzioni. Pertanto non sono più necessarie funzioni di randomizzazione fantasiose a meno che non si desideri utilizzare un tipo di randomizzatore specifico.


1
Ho osservato questo e ho pensato che dovesse essere sbagliato perché (max - min) = 5, producendo un numero intero casuale compreso tra 0 e 4 (più 1 che fa da 1 a 5). Ma inserendo il codice in un parco giochi Xcode era evidente che funzionava. Il motivo è che max è effettivamente uguale a 7 poiché endIndex restituisce "La prima posizione 'oltre la fine' della raccolta." (come indicato nella documentazione di Apple). Quindi, una buona risposta e un utile esercizio di apprendimento per me.
Vince O'Sullivan,

Funziona anche con numeri interi negativi. randomNumber(-3 ... -1)funziona fintanto che hai spazi prima e dopo il .... Puoi usare anche random(-3 ..< -1per escludere l'ultimo numero.
Carter Medlin,

Utilizzare ClosedIntervalinvece di Rangese si desidera avere questo lavoro con numeri non interi.
Carter Medlin,

Non lo farei. I tipi di intervallo sono stati deprecati in Swift 3. Probabilmente esiste un modo per utilizzare Generics per espandere la funzionalità del codice, ma non ho avuto il tempo, l'inclinazione o la ragione per indagare.
Ash,

1
Eccoci, una versione intera generica del codice.
Ash,


18

Se vuoi, lo creo per numeri casuali. questa è l'estensione del numero Int e 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
    }
}

USO :

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)

operatore binario / non può essere applicato a due operandi doppi
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

Questo perché arc4random_uniform () è definito come segue:

func arc4random_uniform(_: UInt32) -> UInt32

Prende un UInt32 come input e sputa un UInt32. Stai tentando di passargli un intervallo di valori. arc4random_uniform ti dà un numero casuale compreso tra 0 e il numero che lo passi (esclusivamente), quindi se, ad esempio, volessi trovare un numero casuale compreso tra -50 e 50, come [-50, 50]puoi usarearc4random_uniform(101) - 50


Sky ha risposto perfettamente alla mia domanda Credo che tu stia dicendo la stessa cosa e grazie mille posso confermare che impostando dice1,2 = arc4random_uniform (6) +1 ha effettivamente impostato l'intervallo su 1-6 Ho provato questo con un'affermazione: D
arcreigh,

6

Ho modificato la risposta di @DaRk -_- D0G per lavorare con Swift 2.0

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

La soluzione più veloce qui! Molte grazie!
Andrew


3

In rapido ...

Questo è inclusivo, la chiamata random(1,2)restituirà un 1 o un 2, Funzionerà anche con numeri negativi.

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

3

La risposta è solo 1 codice di riga:

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

La soluzione alternativa è:

    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
}

Sebbene lo svantaggio sia che il numero non può iniziare da 0.


2

Da Swift 4.2:

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

Usato come:

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

2

Modifica: Swift 4.2+ fornisce ora questo:

(100...200).randomElement()

È idiomatico per me estendere 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 uso:

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

Probabilmente solo una cosa stilistica. Non c'è alcun vantaggio intrinseco in nessuno dei due metodi, è proprio quello con cui ti senti più a tuo agio.
Ash,

1
Per le persone che considerano questa “stilistica” Ho una raccomandazione lingua per loro: C. Divertiti!
MXC

Sono sicuro che qualcuno aveva già fatto 3 anni fa :) stackoverflow.com/questions/34712453/...
Leo Dabus

1

Ho completato con successo la creazione di un numero casuale utilizzando il seguente codice:

var coin = arc4random_uniform(2) + 1

Spero che questo possa aiutarti.


0

Soluzione Swift 3 Xcode Beta 5. Basato sulla risposta di Ted van Gaalen.

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

spero che funzioni. fare un numero casuale nell'intervallo per arc4random_uniform ()?

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

0

Probabilmente uno trova utile questa versione un po 'aggiornata Rangedell'estensione dalla risposta di Ted van Gaalen usando Swift 4 / Xcode 9+ :

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)

O questa soluzione un po '"confusa" per supportare intervalli aperti e chiusi:

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
}

Non sono sicuro se esiste un modo per aggiungere proprietà a entrambi i tipi di intervalli contemporaneamente.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.