Gerando números aleatórios com Swift


92

Preciso gerar um número aleatório.

Parece que a arc4randomfunção não existe mais, bem como a arc4random_uniformfunção.

As opções que tenho são arc4random_stir(), arc4random_buf(UnsafeMutablePointer<Void>, Int)e arc4random_addrandom(UnsafeMutablePointer<UInt8>, Int32).

Não consigo encontrar nenhum documento sobre as funções e nenhum comentário nos arquivos de cabeçalho fornece dicas.


3
Parece que o autocompletar no Xcode acabou de quebrar. Eu poderia jurar que digitei sem autocompletar e ele não compilou. Trabalhando agora. Boa referência de @arsen
Big_Mac

1
arc4random_uniform está disponível. É parte da API Foundation, não uma parte nativa da linguagem, portanto, você precisa de um "import Foundation" (ou "import UIKit") no cabeçalho do arquivo para torná-lo disponível.
Vince O'Sullivan

probabilidade = Int (arc4random_uniform (UInt32 (total))) - porque o início de digitação está quebrado, as reclamações de digitação não eram específicas, essa era minha reclamação de elenco proveniente de dois erros diferentes
bshirley

Respostas:


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

Sob o capô, o Swift usa arc4random_bufpara fazer o trabalho.

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

arc4random()retorna um número aleatório no intervalo de 0 a 4 294 967 295

drand48()retorna um número aleatório no intervalo de 0,0 a 1,0

arc4random_uniform(N)retorna um número aleatório no intervalo de 0 a N - 1

Exemplos:

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

arc4random_uniform () é recomendado sobre construções como arc4random() % upper_bound, pois evita "modulo bias" quando o limite superior não é uma potência de dois.


Float.random()atualmente está marcado como Beta , e assim dá'Float' has no member 'random'
Dale

22

Você também pode tentar:

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

Eu tive que adicionar "UInt32" para fazer funcionar.


1
Quando procuro esta função, vejo public func arc4random_uniform(_: UInt32) -> UInt32. Então, estou me perguntando por que converter para o parâmetro em UInt32? Algo mais está acontecendo aqui?
Mark Moeykens

8

Basta chamar esta função e fornecer o intervalo mínimo e máximo do número e você obterá um número aleatório.

por exemplo, como randomNumber (MIN: 0, MAX: 10) e você obterá um número entre 0 e 9 .

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

Nota: - Você sempre obterá um número inteiro de saída.


1
Eu acho que precisa ser: func randomNumber(MIN: Int, MAX: Int)-> Int{ return Int(arc4random_uniform(UInt32(MAX-MIN)) + UInt32(MIN)); }
Adahus

5

Após alguma investigação, escrevi isto:

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

Agora você pode simplesmente fazer Math.randomFraction()para obter números aleatórios [0..1 [sem ter que se lembrar da propagação primeiro. Espero que isso ajude alguém: o)


4

Atualização com o 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

Outra opção é usar o 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 tem um período de 2 ^ 128-1 e passa em todos os testes do conjunto de testes BigCrush . Observe que, embora este seja um gerador de números pseudo-aleatórios de alta qualidade com um longo período, não é um gerador de números aleatórios criptograficamente seguro .

Você poderia semeá-lo a partir do tempo atual ou de qualquer outra fonte aleatória de entropia. Por exemplo, se você tivesse uma função chamada urand64()que lia um UInt64de /dev/urandom, você poderia usá-la assim:

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 que você não fornece uma explicação para este código?
reformado

1

Em Swift 3:

Irá gerar um número aleatório entre 0 para limitar

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

e se eu quiser gerar um número aleatório de 5 a 10, não de 0 a n número
Rishi

1
@Rishi De 5 a 10 seriaarc4random_uniform(6) + 5
Matt Le Fleur

1

Minha implementação como uma extensão Int. Irá gerar números aleatórios no intervalofrom..<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

É assim que obtenho um número aleatório entre 2 int's!

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

Outra opção é usar GKMersenneTwisterRandomSource do GameKit. Os documentos dizem:

Uma fonte pseudo-aleatória determinística que gera números aleatórios com base em um algoritmo mersenne twister. Esta é uma fonte aleatória determinística adequada para criar mecânicas de jogo confiáveis. É um pouco mais lento do que uma fonte Arc4, mas mais aleatório, pois tem um período mais longo para repetir as sequências. Embora seja determinística, esta não é uma fonte criptográfica aleatória. No entanto, é adequado para ofuscar os dados do jogo.

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)

Exemplo retirado do código de amostra da Apple: https://github.com/carekit-apple/CareKit/blob/master/CareKitPrototypingTool/OCKPrototyper/CareKitPatient/RandomNumberGeneratorHelper.swift


1

Estou atrasado para a festa 🤩🎉

Usar uma função que permite alterar o tamanho da matriz e a seleção do intervalo em tempo real é o método mais versátil. Você também pode usar o mapa, por isso é muito conciso. Eu o uso em todos os meus testes de desempenho / avaliação de desempenho.

elementsé o número de itens na matriz,
incluindo apenas números de0...max

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

O Code Sense / Placeholders se parece com isto. randArr(elements: Int, max: Int)

10 elementos em minha matriz variando de 0 a 1000.

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

0

você pode usar isso na taxa 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

Vamos codificar com Swift para o número aleatório ou string aleatória :)

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

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

ele lhe dará a saída aleatoriamente.


0

Não se esqueça que alguns números se repetirão! então você precisa fazer algo como ....

meu total de perguntas era 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

olha, eu tive o mesmo problema, mas eu insiro a função como uma variável global

Como

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

func GetCase(){

your code
}

obviamente isso não é eficiente, então eu apenas copio e colo o código na função para que possa ser reutilizável, então o xcode sugere que eu defina a var como constante para que meu código seja

func GetCase() {

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

   if categoria == 1 {
    }
}

bem, isso é uma parte do meu código, então o xcode me diz algo sobre inmutável e inicialização, mas ele compila o aplicativo de qualquer maneira e esse conselho simplesmente desaparece

espero que ajude

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.