¿Cómo se hace un número aleatorio entre rango para arc4random_uniform ()?


129

así que mi objetivo en este codebit es lanzar dos dados al azar y, como todos sabemos, su dado regular solo tiene 6 lados, así que importé Foundation para acceder a arc4random_uniform (UInt32). Intenté usar el rango de (1..7) para evitar obtener 0 al azar, sin embargo, eso arrojó un error que no disfruté demasiado. Traté de hacer esto:

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

sin embargo eso regresó

No se pudo encontrar una sobrecarga para 'init' que acepte los argumentos proporcionados

Espero que esta sea suficiente información para que ustedes tengan deudas increíbles para ayudarme :)

Tenga en cuenta que solo estoy haciendo esto en un patio de recreo para practicar rápido. No es imperativo que aprenda a hacer esto; solo soy yo jugando antes de saltar a crear aplicaciones reales: 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

Esto devuelve un error de 'Rango $ T3' no es convertible a 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.")

44
Creo que debe hacer dice1 = arc4random_uniform(6) + 1para obtener el rango 1 - 6. Sin embargo, no hago el objetivo C de iOS ni tengo ningún conocimiento sobre lenguaje rápido. El método aleatorio debería devolverle 0 - 5, y + 1 será 1 - 6.
Sky

1
El rango es un objeto de datos en sí mismo, no es un dato entero, es por eso que obtiene el error cuando el argumento solo toma (UInt32) -u_int32_t arc4random_uniform(u_int32_t upper_bound);
Sky

aha! gracias cielo! hice una afirmación para probar si iba a menos de 0 y puedo confirmar que esto era exactamente lo que necesitaba. ¡Póngalo como respuesta para que pueda marcarlo como tal!
arcreigh

probabilidad = Int (arc4random_uniform (UInt32 (total))) - si tiene múltiples quejas de conversión que no son específicas (porque el encabezado / encabezados no son funcionales)
bshirley

Esto se construye comenzando con Swift 4.2 como se señala a continuación stackoverflow.com/a/50696901/1148030
Peter Lamberg

Respuestas:


260

Creo que deberias hacer

dice1 = arc4random_uniform(6) + 1;

para obtener el rango 1 - 6. Sin embargo, no hago el objetivo C de iOS ni tengo ningún conocimiento sobre lenguaje rápido. El método aleatorio debe devolver un valor entre 0 y 5, y + 1 lo convertirá en un valor entre 1 y 6.

Si necesita un rango entre digamos 10-30, simplemente haga

int random = arc4random_uniform(21) + 10;

2
@JoeSmith tiene toda la razón en esto, debería ser arc4random_uniform (21) +10 para devolver un rango entre 10-30, ya que el límite superior no es inclusivo. La parte "arc4random_uniform (20) +10" se basa en la edición y los votos de la comunidad.
Cielo

Sí, acabo de probar y para obtener un color aleatorio (es decir, querer un valor aleatorio entre 0 y 255), utilicé: "arc4random_uniform (256) + 0"
Chris Allinson

91

He hecho una extensión de tipo Int. Lo probé en el patio de recreo, espero que esto sea útil. También acepta rangos negativos:

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

usar como

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

o definirlo como una extensión de Rango como una propiedad como esta:

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

66
Su extensión es hermosa: 3 ¡Un verdadero uso de Swift!
Kalzem

Me gusta la extensión Range.
David James

Buena respuesta. Mi única advertencia sería decir que randomInt: no es una extensión natural de Int o Range. Simplemente agregaría esto como una función independiente en un archivo de utilidades.
Vince O'Sullivan

Necesita actualizarse para Swift 3, reemplace range.startIndex con range.lowerBound en su lugar y endIndex ahora es upperBound
Joseph Astrahan

62

Muy buenas respuestas, pero solo quería compartir mi función favorita de generación de números aleatorios Swift para enteros positivos:

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

Aquí hay una actualización rápida para Swift 3 y, como beneficio adicional, ahora funciona para cualquier tipo de valor que se ajuste al protocolo SignedInteger, mucho más conveniente para aplicaciones de datos centrales que necesitan especificar Int16, Int32, etc. Como nota rápida, si usted Realmente necesito que funcione también en enteros sin signo, solo copie la función completa y luego reemplace SignedIntegercon UnsignedIntegery 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

Gracias a la eliminación de toIntMax () en Swift 4, ahora tenemos que usar un medio diferente para convertir a un tipo entero común. En este ejemplo, estoy usando Int64, que es lo suficientemente grande para mis propósitos, pero si está usando enteros sin signo o tiene un tipo personalizado Int128 o Int256, debe usarlos.

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

Una más, para el phile aleatorio total, aquí hay una extensión que devuelve un elemento aleatorio de cualquier Collectionobjeto tipo. Tenga en cuenta que esto utiliza la función anterior para generar su índice, por lo que necesitará ambos.

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

devuelve un número aleatorio entre 1 y 6.

randomNumber(50...100)

devuelve un número entre 50 y 100 inclusive. Naturalmente, puede reemplazar los valores de 50 y 100 con lo que quiera.

Swift 4.2

Por desgracia, mi mejor respuesta de StackOverflow se ha vuelto obsoleta por fin. Ahora puede usar simplemente Int.random(in: 1 ... 6)para generar un número aleatorio en un rango dado. También funciona para otras formas de número entero y de coma flotante. Los tipos de colección ahora también proporcionan shuffle()y randomElement()funciones. Por lo tanto, ya no es necesario utilizar funciones de aleatorización sofisticadas a menos que desee utilizar un tipo de aleatorizador específico.


1
Miré esto y pensé que debía estar mal porque (max - min) = 5, produciendo un número entero aleatorio en el rango de 0 a 4 (más 1 haciendo 1 a 5). Pero al poner el código en un patio de juegos Xcode fue evidente que funcionó. La razón es que max es en realidad igual a 7, ya que endIndex devuelve "La primera posición de la colección 'pasado el final'". (como se indica en la documentación de Apple). Entonces, una buena respuesta y un útil ejercicio de aprendizaje para mí.
Vince O'Sullivan

Esto también funciona con enteros negativos. randomNumber(-3 ... -1)funciona siempre que tenga espacios antes y después de .... También puede usar random(-3 ..< -1para excluir el último número.
Carter Medlin

Úselo en ClosedIntervallugar de Rangesi desea que esto funcione con números no enteros.
Carter Medlin

Yo no lo haría Los tipos de intervalo quedaron en desuso en Swift 3. Probablemente haya una forma de usar los genéricos para expandir la funcionalidad del código, pero no he tenido el tiempo, la inclinación o la razón para investigar.
Ash

1
Ahí vamos, una versión entera genérica del código.
Ash


18

Si quieres, creo eso para números aleatorios. esta es la extensión del número Int y 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
    }
}

UTILIZAR :

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)

operador binario / no se puede aplicar a dos operandos dobles
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

Esto se debe a que arc4random_uniform () se define de la siguiente manera:

func arc4random_uniform(_: UInt32) -> UInt32

Toma un UInt32 como entrada y escupe un UInt32. Estás intentando pasarle un rango de valores. arc4random_uniform le da un número aleatorio entre 0 y el número que lo pasa (exclusivamente), por lo que si, por ejemplo, desea encontrar un número aleatorio entre -50 y 50, ya [-50, 50]que podría usararc4random_uniform(101) - 50


Sky respondió a mi pregunta perfectamente. Creo que también está diciendo lo mismo. Muchas gracias. Puede confirmar que al establecer dados1,2 = arc4random_uniform (6) +1 realmente estableció el rango en 1-6. Probé esto con una afirmación: D
arcreigh

6

Modifiqué la respuesta de @DaRk -_- D0G para trabajar 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 solución más rápida aquí! ¡Muchas gracias!
Andrew


3

En rápido ...

Esto es inclusivo, las llamadas random(1,2)devolverán un 1 o un 2, esto también funcionará con números negativos.

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

3

La respuesta es solo 1 código de línea:

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 solución alternativa es:

    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
}

Aunque el inconveniente es que ese número no puede comenzar desde 0.


2

Desde Swift 4.2:

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

Usado como:

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

2

Editar: Swift 4.2+ proporciona esto ahora:

(100...200).randomElement()

Es idiomático para mí extender 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)))
    }
}

En uso:

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

Probablemente solo una cosa estilística. No existe una ventaja inherente a ninguno de los métodos, es simplemente con lo que se sienta más cómodo.
Ash

1
Para las personas que consideran este “estilística” Tengo una recomendación idioma para ellos: C. ¡Que te diviertas!
mxcl

Estoy seguro de que alguien ya lo había hecho hace 3 años :) stackoverflow.com/questions/34712453/…
Leo Dabus

1

Logré crear un número aleatorio con éxito usando el siguiente código:

var coin = arc4random_uniform(2) + 1

Espero que esto le pueda ayudar.


0

Solución Swift 3 Xcode Beta 5. Basado en la respuesta de 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

Espero que esto esté funcionando. hacer un número aleatorio entre rango para arc4random_uniform ()?

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

0

Probablemente uno encuentre útil esta versión un poco actualizada de la Rangeextensión de la respuesta de 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 esta es una solución un poco "hacky" para admitir intervalos abiertos y cerrados:

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
}

No estoy seguro de si hay una manera de agregar propiedades a ambos tipos de intervalos simultáneamente.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.