Generando números aleatorios con Swift


92

Necesito generar un número aleatorio.

Parece que la arc4randomfunción ya no existe tan bien como la arc4random_uniformfunción.

Las opciones que tengo son arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int)y arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).

No puedo encontrar ningún documento sobre las funciones y ningún comentario en los archivos de encabezado da pistas.


3
Parece que el autocompletado en Xcode se rompió. Podría haber jurado que lo escribí sin autocompletar y no se compiló. Trabajando ahora. Buena referencia de @arsen
Big_Mac

1
arc4random_uniform está disponible. Es parte de la API Foundation, no una parte nativa del lenguaje, por lo que necesita una "importación Foundation" (o "import UIKit") al principio del archivo para que esté disponible.
Vince O'Sullivan

probabilidad = Int (arc4random_uniform (UInt32 (total))) - debido a que el mecanografiado está roto, las quejas de mecanografía no eran específicas, esa fue mi queja de casting proveniente de dos errores diferentes
bshirley

Respuestas:


227

===== Swift 4.2 / Xcode 10 =====

let randomIntFrom0To10 = Int.random(in: 1..<10)
let randomFloat = Float.random(in: 0..<1)

// if you want to get a random element in an array
let greetings = ["hey", "hi", "hello", "hola"]
greetings.randomElement()

Swift utiliza bajo el capó arc4random_bufpara hacer su trabajo.

===== Swift 4.1 / Xcode 9 =====

arc4random()devuelve un número aleatorio en el rango de 0 a 4294967295

drand48()devuelve un número aleatorio en el rango de 0.0 a 1.0

arc4random_uniform(N)devuelve un número aleatorio en el rango de 0 a N - 1

Ejemplos:

arc4random() // => UInt32 = 2739058784
arc4random() // => UInt32 = 2672503239
arc4random() // => UInt32 = 3990537167
arc4random() // => UInt32 = 2516511476
arc4random() // => UInt32 = 3959558840

drand48() // => Double = 0.88642843322303122
drand48() // => Double = 0.015582849408328769
drand48() // => Double = 0.58409022031727176
drand48() // => Double = 0.15936862653180484
drand48() // => Double = 0.38371587480719427

arc4random_uniform(3) // => UInt32 = 0
arc4random_uniform(3) // => UInt32 = 1
arc4random_uniform(3) // => UInt32 = 0
arc4random_uniform(3) // => UInt32 = 1
arc4random_uniform(3) // => UInt32 = 2

Se recomienda arc4random_uniform () sobre construcciones como, arc4random() % upper_boundya que evita el "sesgo de módulo" cuando el límite superior no es una potencia de dos.


Float.random()actualmente está marcado como Beta , por lo que da'Float' has no member 'random'
Dale

22

También podrías intentarlo:

let diceRoll = Int(arc4random_uniform(UInt32(6)))

Tuve que agregar "UInt32" para que funcione.


1
Cuando busco esta función, veo public func arc4random_uniform(_: UInt32) -> UInt32. Entonces me pregunto por qué convertir al parámetro a UInt32? ¿Está pasando algo más aquí?
Mark Moeykens

8

Simplemente llame a esta función y proporcione un rango mínimo y máximo de números y obtendrá un número aleatorio.

por ejemplo, como randomNumber (MIN: 0, MAX: 10) y obtendrá un número entre 0 y 9 .

func randomNumber(MIN: Int, MAX: Int)-> Int{
    return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN));
}

Nota: - Siempre obtendrá como resultado un número entero.


1
Creo que ha de ser: func randomNumber(MIN: Int, MAX: Int)-> Int{ return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN)); }
Adahus

5

Después de algunas investigaciones escribí esto:

import Foundation

struct Math {
   private static var seeded = false

   static func randomFractional() -> CGFloat {

      if !Math.seeded {
         let time = Int(NSDate().timeIntervalSinceReferenceDate)
         srand48(time)
         Math.seeded = true
      }

      return CGFloat(drand48())
   }
}

Ahora puede hacer Math.randomFraction()para obtener números aleatorios [0..1 [sin tener que recordar la siembra primero. Espero que esto ayude a alguien: o)


4

Actualización con swift 4.2:

let randomInt = Int.random(in: 1..<5)
let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)

3

Otra opción es utilizar el algoritmo xorshift128plus :

func xorshift128plus(seed0 : UInt64, _ seed1 : UInt64) -> () -> UInt64 {
    var state0 : UInt64 = seed0
    var state1 : UInt64 = seed1
    if state0 == 0 && state1 == 0 {
        state0 = 1 // both state variables cannot be 0
    }

    func rand() -> UInt64 {
        var s1 : UInt64 = state0
        let s0 : UInt64 = state1
        state0 = s0
        s1 ^= s1 << 23
        s1 ^= s1 >> 17
        s1 ^= s0
        s1 ^= s0 >> 26
        state1 = s1
        return UInt64.addWithOverflow(state0, state1).0
    }

    return rand
}

Este algoritmo tiene un período de 2 ^ 128 - 1 y pasa todas las pruebas de la suite de pruebas BigCrush . Tenga en cuenta que si bien este es un generador de números pseudoaleatorios de alta calidad con un período largo, no es un generador de números aleatorios criptográficamente seguro .

Puede sembrarlo desde el momento actual o desde cualquier otra fuente aleatoria de entropía. Por ejemplo, si tuvieras una función llamada urand64()que lea un UInt64de /dev/urandom, podrías usarlo así:

let rand = xorshift128plus(urand64(), urand64())
for _ in 1...10 {
    print(rand())
}

1
let MAX : UInt32 = 9
let MIN : UInt32 = 1 
func randomNumber()
{
   var random_number = Int(arc4random_uniform(MAX) + MIN)
   print ("random = ", random_number);    
}

¿Por qué no proporciona una explicación para este código?
reformado

1

En Swift 3:

Generará un número aleatorio entre 0 para limitar

let limit : UInt32 = 6
print("Random Number : \(arc4random_uniform(limit))")

y si quiero generar un número aleatorio del 5 al 10, no del 0 al número n
Rishi

1
@Rishi De 5 a 10 seríaarc4random_uniform(6) + 5
Matt Le Fleur

1

Mi implementación como una extensión Int. Generará números aleatorios en el rangofrom..<to

public extension Int {
    static func random(from: Int, to: Int) -> Int {
        guard to > from else {
            assertionFailure("Can not generate negative random numbers")
            return 0
        }
        return Int(arc4random_uniform(UInt32(to - from)) + UInt32(from))
    }
}

1

¡Así es como obtengo un número aleatorio entre 2 int!

func randomNumber(MIN: Int, MAX: Int)-> Int{
    var list : [Int] = []
    for i in MIN...MAX {
        list.append(i)
    }
    return list[Int(arc4random_uniform(UInt32(list.count)))]
}

uso:

print("My Random Number is: \(randomNumber(MIN:-10,MAX:10))")

1

Otra opción es utilizar GKMersenneTwisterRandomSource de GameKit. Los doctores dicen:

Una fuente pseudoaleatoria determinista que genera números aleatorios basados ​​en un algoritmo de mersenne twister. Esta es una fuente aleatoria determinista adecuada para crear mecánicas de juego confiables. Es un poco más lento que una fuente Arc4, pero más aleatorio, ya que tiene un período más largo hasta que se repiten secuencias. Si bien es determinista, esta no es una fuente aleatoria criptográfica. Sin embargo, es adecuado para la ofuscación de los datos del juego.

import GameKit

let minValue = 0
let maxValue = 100

var randomDistribution: GKRandomDistribution?
let randomSource = GKMersenneTwisterRandomSource()
randomDistribution = GKRandomDistribution(randomSource: randomSource, lowestValue: minValue, highestValue: maxValue)
let number = randomDistribution?.nextInt() ?? 0
print(number)

Ejemplo tomado del código de muestra de Apple: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift


1

Llego tarde a la fiesta 🤩🎉

Usar una función que le permite cambiar el tamaño de la matriz y la selección de rango sobre la marcha es el método más versátil. También puede utilizar el mapa para que sea muy conciso. Lo uso en todas mis pruebas de rendimiento / evaluación comparativa.

elementses el número de elementos en la matriz que
solo incluye números de0...max

func randArr(_ elements: Int, _ max: Int) -> [Int] {
        return (0..<elements).map{ _ in Int.random(in: 0...max) }
    }

Code Sense / Placeholders se ven así. randArr(elements: Int, max: Int)

10 elementos en mi matriz que van de 0 a 1000.

randArr(10, 1000) // [554, 8, 54, 87, 10, 33, 349, 888, 2, 77]

0

puede usar esto en una tarifa específica:

let die = [1, 2, 3, 4, 5, 6]
 let firstRoll = die[Int(arc4random_uniform(UInt32(die.count)))]
 let secondRoll = die[Int(arc4random_uniform(UInt32(die.count)))]

0

Permite codificar con Swift para el número aleatorio o la cadena aleatoria :)

let quotes: NSArray = ["R", "A", "N", "D", "O", "M"]

      let randomNumber = arc4random_uniform(UInt32(quotes.count))
      let quoteString = quotes[Int(randomNumber)]
      print(quoteString)

le dará una salida al azar.


0

¡No olvide que algunos números se repetirán! así que necesitas hacer algo como ...

mi total de preguntas fue 47.

func getRandomNumbers(totalQuestions:Int) -> NSMutableArray
{

    var arrayOfRandomQuestions: [Int] = []

    print("arraySizeRequired = 40")
    print("totalQuestions = \(totalQuestions)")

    //This will output a 40 random numbers between 0 and totalQuestions (47)
    while arrayOfRandomQuestions.count < 40
    {

        let limit: UInt32 = UInt32(totalQuestions)

        let theRandomNumber = (Int(arc4random_uniform(limit)))

            if arrayOfRandomQuestions.contains(theRandomNumber)
            {
                print("ping")

            }
            else
            {
            //item not found
                arrayOfRandomQuestions.append(theRandomNumber)
            }

    }

    print("Random Number set = \(arrayOfRandomQuestions)")
    print("arrayOutputCount = \(arrayOfRandomQuestions.count)")


    return arrayOfRandomQuestions as! NSMutableArray

}

-2

mira, tuve el mismo problema pero inserto la función como una variable global

como

var RNumber = Int(arc4random_uniform(9)+1)

func GetCase(){

your code
}

obviamente, esto no es eficiente, así que simplemente copio y pego el código en la función para que pueda ser reutilizable, luego xcode me sugiere que establezca la var como constante para que mi código sea

func GetCase() {

let RNumber = Int(arc4random_uniform(9)+1)

   if categoria == 1 {
    }
}

bueno, eso es parte de mi código, así que xcode me dice algo de inmutable e inicialización, pero de todos modos construye la aplicación y ese consejo simplemente desaparece

Espero eso ayude

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.