¿Cómo se genera un número aleatorio en el lenguaje Swift de Apple?


443

Me doy cuenta de que el libro Swift proporcionó una implementación de un generador de números aleatorios. ¿Es la mejor práctica copiar y pegar esta implementación en el propio programa? ¿O hay una biblioteca que hace esto que podemos usar ahora?

Respuestas:


466

Swift 4.2+

Swift 4.2 incluido con Xcode 10 presenta nuevas funciones aleatorias fáciles de usar para muchos tipos de datos. Puede llamar al random()método en tipos numéricos.

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

77
No tuve que importar explícitamente a Darwin
finneycanhelp

3
En mi archivo Playground necesitaba importar Darwin porque no estaba importando nada más.
DonnaLea

SoliQuiD: excepto omite el guión bajo adicional después de arc4, es decir, arc4random_uniform (5).
Ali Beadle

3
Advertencia : Se ha demostrado que RC4 o arc4 son distinguibles de los valores aleatorios puros . Entonces, aunque arc4 (un cifrado de flujo) suena criptográficamente seguro, en realidad no lo es.
Maarten Bodewes

2
@MaartenBodewes: ya no es directamente relevante para esta respuesta, pero arc4random en realidad no usa el cifrado RC4, a pesar de su nombre, en macOS o BSD. Utiliza un CSPRNG proporcionado por el sistema en macOS y ChaCha20 en la mayoría de los BSD. El RNG predeterminado de Swift (como se usa en esta respuesta) lo llama como un detalle de implementación en macOS, pero usa un generador subyacente apropiado en cada plataforma compatible.
Stephen Canon

496

Úselo arc4random_uniform(n)para un entero aleatorio entre 0 y n-1.

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

Transmita el resultado a Int para que no tenga que escribir explícitamente sus vars como UInt32(lo que parece no Swifty).


77
Muy simple. Me gusta. ¡Votación a favor! Pero un dado real no tiene 0. En su código, diceRollpodría ser 0. Solo digo ...
MK Safi

61
Sí, de verdad quieres Int(arc4random_uniform(6)+1).
Michael Dorst

55
probabilidad = Int (arc4random_uniform (UInt32 (total))) - también tuve que lanzar a UInt32
bshirley

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

No olvide convertir el parámetro, n, ingresado en arc3random_uniform(n)a UInt32(n)si está utilizando un valor que aún no es de ese tipo.
Dave Fontenot

117

Editar: actualizado para Swift 3.0

arc4randomfunciona bien en Swift, pero las funciones básicas están limitadas a tipos enteros de 32 bits ( Intes de 64 bits en iPhone 5S y Macs modernos). Aquí hay una función genérica para un número aleatorio de un tipo expresable por un literal entero:

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

Podemos usar esta nueva función genérica para extender UInt64, agregar argumentos de límite y mitigar el sesgo de módulo. (Esto se levanta directamente de arc4random.c )

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

Con eso podemos extendernos Int64a los mismos argumentos, lidiando con el desbordamiento:

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

Para completar la familia ...

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

Después de todo eso, finalmente podemos hacer algo como esto:

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

No compila: var r = arc4random(UInt64). Por favor consejo, ¿qué quisiste decir aquí?
Ossir

@Ossir compila bien para mí ... significa llamar a la función arc4random(definida en el primer bloque de código) con el argumento UInt64que es a Type.
jstn

¿Arc4random_buf (y, por lo tanto, todas las extensiones de 64 bits) sufren de sesgo de módulo?
Matthew Seaman

El sesgo de módulo solo entra en juego cuando agrega un límite superior, por lo que no se aplica arc4random_buf. El propósito de estas extensiones es hacer exactamente lo que arc4random_uniformhace (mitigar el sesgo de módulo) excepto para los tipos de 64 bits.
jstn

al usar las funciones flotantes, ¿cómo puedo incluir el valor superior en el rango de posibilidades? Entonces digamos que hago 0.0 como el inferior y 1.0 como el superior. Con esta lógica, me dará 0.0 hasta 0.99999999. Pero en cambio me gustaría incluir el 1.0 como una posibilidad. ¿Cómo puedo conseguir esto?
MobileMon

80

Editar para Swift 4.2

A partir de Swift 4.2, en lugar de usar la función C importada arc4random_uniform (), ahora puede usar las funciones nativas de Swift.

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

También puede usar random(in:)para obtener valores aleatorios para otros valores primitivos; como Int, Double, Float e incluso Bool.

Versiones Swift <4.2

Este método generará un Intvalor aleatorio entre el mínimo y el máximo dados

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

61

Usé este código:

var k: Int = random() % 10;

20
primero debe llamar a srandom (UInt32 (time (nil)))), de lo contrario siempre devolverá la misma secuencia de números
Hola Soy Edu Feliz Navidad

3
Leí el documento de Apple al azar () dos veces, pero no pude deducir su uso ... Ojalá simplemente incluyeran un ejemplo de código simple como este en la parte superior. "La función random () utiliza un generador de números aleatorios no lineal y de retroalimentación aditiva, empleando una tabla predeterminada de enteros largos de tamaño 31. Devuelve números pseudoaleatorios sucesivos en el rango de 0 a (2 31) -1. El período de este generador de números aleatorios es muy grande, aproximadamente 16 * ((2 31) -1) ". ... Muchas gracias manzana ... Me aseguraré de hacer referencia a esto en mi próxima tesis.
nocarrier

1
random () a veces conduce a un bloqueo repentino en iPads. Si esto sucede, use arc4random_uniform (6) desde arriba. Si usa random (), puede crear más valores aleatorios anteponiendo srandomdev ().
JackPearse

1
Tengo mensaje de error del compilador:random is unavailable in Swift: Use arc4random instead.
Mike Keskinov

1
Esta solución tiene un sesgo de módulo: zuttobenkyou.wordpress.com/2012/10/18/…
rgov

33

A partir de iOS 9, puedes usar las nuevas clases de GameplayKit para generar números aleatorios de varias maneras.

Tiene cuatro tipos de fuente para elegir: una fuente aleatoria general (sin nombre, hasta el sistema para elegir lo que hace), lineal congruencial, ARC4 y Mersenne Twister. Estos pueden generar entradas aleatorias, flotantes y bools.

En el nivel más simple, puede generar un número aleatorio a partir de la fuente aleatoria incorporada del sistema de esta manera:

GKRandomSource.sharedRandom().nextInt()

Eso genera un número entre -2,147,483,648 y 2,147,483,647. Si desea un número entre 0 y un límite superior (exclusivo) usaría esto:

GKRandomSource.sharedRandom().nextIntWithUpperBound(6)

GameplayKit tiene algunos constructores convenientes integrados para trabajar con dados. Por ejemplo, puedes tirar un dado de seis lados como este:

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

Además, puede dar forma a la distribución aleatoria utilizando elementos como GKShuffledDistribution. Eso requiere un poco más de explicación, pero si estás interesado, puedes leer mi tutorial sobre los números aleatorios de GameplayKit .


1
Gracias por este consejo, es una de las mejores respuestas. Para usar estas funciones hay que agregar import GameplayKit. Swift 3 cambió la sintaxis aGKRandomSource.sharedRandom().nextInt(upperBound: 6)
petrsyn

77
¿Qué tan pesado es este kit para importar? No quiero hinchar mi código.
μολὼν.λαβέ

25

Puede hacerlo de la misma manera que lo haría en C:

let randomNumber = arc4random()

randomNumberse infiere que es de tipo UInt32(un entero sin signo de 32 bits)


12
Adición: rand, arc4random, drand48y amigos están todos en el Darwinmódulo. Ya se importó para usted si está creando una aplicación Cocoa, UIKit o Foundation, pero lo necesitará import Darwinen los parques infantiles.
rickster

55
Y no intente transmitir el resultado de arc4random () a un Int: esto funcionará bien en una plataforma de 64 bits, pero en una plataforma de 32 bits, los Ints están firmados por 32 bits, por lo que obtendrá negativos inesperados números. Esto ya ha hecho tropezar a algunas personas, así que pensé en mencionarlo aquí.
Matt Gibson el

23

Utilizar arc4random_uniform()

Uso:

arc4random_uniform(someNumber: UInt32) -> UInt32

Esto le da enteros aleatorios en el rango 0de someNumber - 1.

El valor máximo para UInt324,294,967,295 (es decir, 2^32 - 1).

Ejemplos:

  • Lanzamiento de moneda

    let flip = arc4random_uniform(2) // 0 or 1
  • Tirada de dados

    let roll = arc4random_uniform(6) + 1 // 1...6
  • Día aleatorio en octubre

    let day = arc4random_uniform(31) + 1 // 1...31
  • Año aleatorio en la década de 1990

    let year = 1990 + arc4random_uniform(10)

Forma general:

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

donde number, maxy minestán UInt32.

Qué pasa...

arc4random ()

También puede obtener un número aleatorio mediante el uso arc4random(), que produce UInt32entre 0 y 2 ^ 32-1. Por lo tanto, para obtener un número aleatorio entre 0y x-1, puede dividirlo entre xy tomar el resto. O, en otras palabras, use el operador restante (%) :

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

Sin embargo, esto produce un ligero sesgo de módulo (ver también aquí y aquí ), por eso arc4random_uniform()se recomienda.

Conversión ay desde Int

Normalmente estaría bien hacer algo como esto para convertir de ida y vuelta entre Inty UInt32:

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

Sin embargo, el problema es que Inttiene un rango de -2,147,483,648...2,147,483,647sistemas de 32 bits y un rango de -9,223,372,036,854,775,808...9,223,372,036,854,775,807sistemas de 64 bits. Compare esto con el UInt32rango de 0...4,294,967,295. El Ude UInt32significa sin firmar .

Considere los siguientes errores:

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

Por lo tanto, solo debe asegurarse de que sus parámetros de entrada estén dentro del UInt32rango y que tampoco necesite una salida que esté fuera de ese rango.


19

Ejemplo para un número aleatorio entre 10 (0-9);

import UIKit

let randomNumber = Int(arc4random_uniform(10))

Código muy fácil, simple y corto.


16

Solo he podido usar rand()para obtener un CI aleatorio. Puedes convertirlo en Int usando algo como esto:

let myVar: Int = Int(rand())

Puede usar su función aleatoria C favorita y simplemente convertirla en valor a Int si es necesario.


Sí, la conversión de tipos puede ser un negocio complicado de lo contrario y dejar que el constructor Int se encargue de esto es un verdadero ahorro de dolor.
Kzrbill

44
Tenga en cuenta que si no está llamando a srand (...) (llámelo solo una vez) antes de usar rand (), la secuencia de números siempre será exactamente la misma entre cada ejecución de su programa. Si no quieres esto, usa arc4random ()
SomeGuy

2
También podría usar random(), que devuelve un en Intlugar de UInt32, y como @SomeGuy mencionó, simplemente llame srandom(arc4random())una vez en cualquier lugar antes de usarlo para asegurarse de que tenga una semilla aleatoria diferente para cada ejecución de su programa.
brittlewis12

1
¿Alguien puede comentar sobre rand () vs arc4random_uniform ()?
Ruben Martinez Jr.

16

La respuesta de @ jstn es buena, pero un poco detallada. Swift se conoce como un lenguaje orientado al protocolo, por lo que podemos lograr el mismo resultado sin tener que implementar un código repetitivo para cada clase en la familia de enteros, agregando una implementación predeterminada para la extensión del protocolo.

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

Ahora podemos hacer:

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

y todas las demás clases de enteros están bien.


11

En Swift 4.2 puede generar números aleatorios llamando al random()método en cualquier tipo numérico que desee, proporcionando el rango con el que desea trabajar. Por ejemplo, esto genera un número aleatorio en el rango de 1 a 9, inclusive en ambos lados

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

También con otros tipos.

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

9

Aquí hay una biblioteca que hace bien el trabajo 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

Me gustaría agregar a las respuestas existentes que el ejemplo del generador de números aleatorios en el libro de Swift es un Generador de congruencia lineal (LCG), es muy limitado y no debería ser excepto por los ejemplos triviales, donde la calidad de la aleatoriedad no No importa en absoluto. Y un LCG nunca debe usarse con fines criptográficos .

arc4random()es mucho mejor y puede usarse para la mayoría de los propósitos, pero nuevamente no debe usarse para propósitos criptográficos.

Si desea algo que garantice su seguridad criptográfica, úselo SecCopyRandomBytes(). Tenga en cuenta que si construye un generador de números aleatorios en algo, alguien más podría terminar (mal) usándolo con fines criptográficos (como contraseña, clave o generación de sal), entonces debería considerar usarlo de SecCopyRandomBytes()todos modos, incluso si su necesidad no lo hace. No es necesario eso.


6

Desde Swift 4.2

Hay un nuevo conjunto de API:

let randomIntFrom0To10 = Int.random(in: 0 ..< 10)
let randomDouble = Double.random(in: 1 ... 10)
  • Todos los tipos numéricos ahora tienen el random(in:)método que toma range.

  • Devuelve un número uniformemente distribuido en ese rango.


TL; DR

Bueno, ¿qué hay de malo en la "buena" vieja manera?

  1. Debe usar las API de C importadas (son diferentes entre plataformas) .

  2. Y además...

¿Qué pasa si te digo que lo aleatorio no es tan aleatorio?

Si usa arc4random() (para calcular el resto) como arc4random() % aNumber, el resultado no se distribuye uniformemente entre el 0y aNumber. Hay un problema llamado sesgo de módulo .

Sesgo de módulo

Normalmente, la función genera un número aleatorio entre 0y MAX (depende del tipo, etc.) . Para hacer un ejemplo rápido y fácil, digamos que el número máximo es 7y le importa un número aleatorio en el rango 0 ..< 2 (o el intervalo [0, 3) si lo prefiere) .

Las probabilidades para números individuales son:

  • 0: 3/8 = 37.5%
  • 1: 3/8 = 37.5%
  • 2: 2/8 = 25%

En otras palabras, es más probable que termines con 0 o 1 que 2 . Por supuesto, tenga en cuenta que esto es extremadamente simplificado y que el número MAX es mucho más alto, lo que lo hace más "justo".

Este problema es abordado por SE-0202 - Unificación aleatoria en Swift 4.2


5

Sin arc4Random_uniform () en algunas versiones de Xcode (en 7.1 se ejecuta pero no se completa automáticamente para mí). Puedes hacer esto en su lugar.

Para generar un número aleatorio de 0-5. primero

import GameplayKit

Entonces

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

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

Aquí 5 se asegurará de que el número aleatorio se genere de cero a cuatro. Puede establecer el valor en consecuencia.


1
Si pasa 5, devolverá 5 resultados posibles de cero a cuatro. 0 ... 4
Leo Dabus

3

Swift 4.2

Adiós para importar Foundation C lib 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. Utiliza random (in :) para generar dígitos aleatorios a partir de rangos.
  2. randomElement () devuelve nil si el rango está vacío, por lo que desenvuelve el Int devuelto? con si se deja.
  3. Utiliza random (in :) para generar un Double, Float o CGFloat aleatorio y random () para devolver un Bool aleatorio.

Más @ articulo.mercadolibre.com.ar


2

El siguiente código producirá un número aleatorio seguro entre 0 y 255:

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

Lo llamas así:

print(UInt8.random)

Para números más grandes se vuelve más complicado.
Esto es lo mejor que se me ocurrió:

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

Estos métodos usan un número aleatorio adicional para determinar cuántos UInt8s se utilizarán para crear el número aleatorio. La última línea convierte el [UInt8]a UInt16o UInt32.

No sé si los dos últimos todavía cuentan como verdaderamente aleatorio, pero puedes modificarlo a tu gusto :)


Inteligentemente evitaste el sesgo introducido por el módulo, +1 para eso. Podrías advertir a los lectores por qué lo hiciste.
jww

Eso es interesante, realmente no consideré que el sesgo de módulo podría estar en juego aquí. Quizás las posibilidades de obtener un número pequeño no son las mismas que obtener un número grande.
Zyphrax

2

Swift 4.2

Swift 4.2 ha incluido una API de números aleatorios nativa y bastante completa en la biblioteca estándar. ( Propuesta de Swift Evolution SE-0202 )

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

Todos los tipos de números tienen el estático aleatorio (en :) que toma el rango y devuelve el número aleatorio en el rango dado


1

Swift 4.2, Xcode 10.1 .

Para iOS, macOS y tvOS, puede usar una fuente aleatoria de todo el sistema en el marco de Xcode GameKit. Aquí puede encontrar la GKRandomSourceclase con su sharedRandom()método de clase:

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

O simplemente use un randomElement()método que devuelva un elemento aleatorio de la colección:

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

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

0

Puedes usar GeneratorOfasí:

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
¿Cómo es Fibonacci al azar?
Nikolai Ruhe

Hola Nikolai, este bloque de código es la versión anterior Swift 1.2. Si prueba el nuevo Swift 2.0. No sería trabajo.
Durul Dalkanat

2
Entiendo, pero aún así me parece un generador de Fibonacci, no números aleatorios, como se pidió en la pregunta.
Nikolai Ruhe

0

Yo uso este código para generar un número aleatorio:

//
//  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
Bienvenido a SO. Se desaconsejan las respuestas de solo código: edite su respuesta para explicar por qué este código responde a la pregunta y cómo funciona. Consulte stackoverflow.com/help/how-to-answer para obtener más información.
Tim Malone

2
Proporcione algún contexto en torno a su respuesta, y bienvenido a stackoverflow. :)
Jonathan Eustace

0

Detalles

xCode 9.1, Swift 4

Solución orientada a las matemáticas (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
}

Uso de la solución (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]

Solución orientada a programadores (2)

No olvide agregar el código de la solución orientada a las matemáticas (1) aquí

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

Uso de la solución (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]

Muestra completa

No olvide agregar los códigos de solución (1) y solución (2) aquí

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

Resultado de la muestra

ingrese la descripción de la imagen aquí


2
Esta respuesta está fuera de tema. La pregunta era cómo generar un número aleatorio. No cómo hacer una biblioteca de números aleatorios. Sheesh
Andrew Paul Simmons el
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.