Sei que o livro Swift forneceu uma implementação de um gerador de números aleatórios. A melhor prática é copiar e colar essa implementação no próprio programa? Ou existe uma biblioteca que faz isso que podemos usar agora?
443
Swift 4.2+
O Swift 4.2 fornecido com o Xcode 10 apresenta novas funções aleatórias fáceis de usar para muitos tipos de dados. Você pode chamar o random()
método em tipos numéricos.
let randomInt = Int.random(in: 0..<6)
let randomDouble = Double.random(in: 2.71828...3.14159)
let randomBool = Bool.random()
Use
arc4random_uniform(n)
para um número inteiro aleatório entre 0 e n-1.Transmitir o resultado para Int para que você não precise digitar explicitamente seus vars como
UInt32
(o que parece não-Swifty).fonte
0
. No seu código,diceRoll
poderia ser0
. Basta dizer ...Int(arc4random_uniform(6)+1)
.arc3random_uniform(n)
aUInt32(n)
se você estiver usando um valor que ainda não é desse tipo.Edit: Atualizado para Swift 3.0
arc4random
funciona bem no Swift, mas as funções básicas são limitadas a tipos inteiros de 32 bits (Int
é de 64 bits no iPhone 5S e em Macs modernos). Aqui está uma função genérica para um número aleatório de um tipo expressável por um literal inteiro:Podemos usar essa nova função genérica para estender
UInt64
, adicionando argumentos de fronteira e atenuando o viés do módulo. (Isso é retirado diretamente do arc4random.c )Com isso, podemos estender
Int64
os mesmos argumentos, lidando com o estouro:Para completar a família ...
Depois de tudo isso, podemos finalmente fazer algo assim:
fonte
var r = arc4random(UInt64)
. Por favor, informe o que você quis dizer aqui?arc4random
(definida no primeiro bloco de código) com o argumentoUInt64
que é aType
.arc4random_buf
. O objetivo dessas extensões é fazer exatamente o quearc4random_uniform
faz (atenuar a polarização do módulo), exceto para os tipos de 64 bits.Editar para o Swift 4.2
A partir do Swift 4.2, em vez de usar a função C importada arc4random_uniform (), agora você pode usar as funções nativas do Swift.
Você também pode usar
random(in:)
para obter valores aleatórios para outros valores primitivos; como Int, Double, Float e até Bool.Versões Swift <4.2
Este método irá gerar um
Int
valor aleatório entre o mínimo e o máximo indicadosfonte
Eu usei este código:
fonte
random is unavailable in Swift: Use arc4random instead.
No iOS 9, você pode usar as novas classes GameplayKit para gerar números aleatórios de várias maneiras.
Você tem quatro tipos de fonte para escolher: uma fonte aleatória geral (sem nome, até o sistema escolher o que faz), congruencial linear, ARC4 e Mersenne Twister. Isso pode gerar entradas, flutuadores e bools aleatórios.
No nível mais simples, você pode gerar um número aleatório a partir da fonte aleatória interna do sistema, como esta:
Isso gera um número entre -2.147.483.648 e 2.147.483.647. Se você deseja um número entre 0 e um limite superior (exclusivo), use este:
O GameplayKit possui alguns construtores de conveniência incorporados para trabalhar com dados. Por exemplo, você pode rolar um dado de seis lados assim:
Além disso, você pode moldar a distribuição aleatória usando coisas como GKShuffledDistribution. Isso leva um pouco mais de explicação, mas se você estiver interessado, pode ler meu tutorial sobre os números aleatórios do GameplayKit .
fonte
import GameplayKit
. Swift 3 alterou a sintaxe paraGKRandomSource.sharedRandom().nextInt(upperBound: 6)
Você pode fazer da mesma maneira que faria em C:
randomNumber
é inferido como sendo do tipoUInt32
(um número inteiro não assinado de 32 bits)fonte
rand
,arc4random
,drand48
e amigos estão todos noDarwin
módulo. Ele já foi importado para você se você estiver criando um aplicativo Cocoa, UIKit ou Foundation, mas será necessárioimport Darwin
em playgrounds.Usar
arc4random_uniform()
Uso:
arc4random_uniform(someNumber: UInt32) -> UInt32
Isso fornece números inteiros aleatórios no intervalo
0
desomeNumber - 1
.O valor máximo para
UInt32
é 4.294.967.295 (ou seja,2^32 - 1
).Exemplos:
Coin flip
Rolar os dados
Dia aleatório em outubro
Ano aleatório nos anos 90
Forma geral:
onde
number
,max
emin
estãoUInt32
.A respeito...
arc4random ()
Você também pode obter um número aleatório usando
arc4random()
, que produzUInt32
entre 0 e 2 ^ 32-1. Assim, para obter um número aleatório entre0
ex-1
, você pode dividi-lox
e pegar o restante. Ou, em outras palavras, use o Operador restante (%) :No entanto, isso produz um leve viés de módulo (veja também aqui e aqui ), e é por isso que
arc4random_uniform()
é recomendado.Convertendo de e para
Int
Normalmente, seria bom fazer algo assim para converter entre
Int
eUInt32
:O problema, porém, é que
Int
tem um intervalo de-2,147,483,648...2,147,483,647
sistemas de 32 bits e um de-9,223,372,036,854,775,808...9,223,372,036,854,775,807
sistemas de 64 bits. Compare isso com oUInt32
intervalo de0...4,294,967,295
. OU
deUInt32
significa não assinado .Considere os seguintes erros:
Portanto, você só precisa ter certeza de que seus parâmetros de entrada estão dentro do
UInt32
intervalo e também não precisa de uma saída que esteja fora desse intervalo.fonte
Exemplo para número aleatório entre 10 (0-9);
Código muito fácil - simples e curto.
fonte
Consegui usar apenas
rand()
para obter um CInt aleatório. Você pode torná-lo um Int usando algo como isto:Você pode usar sua função aleatória C favorita e apenas converter em valor para Int, se necessário.
fonte
random()
, que retorna umInt
e nãoUInt32
- e, como o @SomeGuy mencionado, simplesmente chamesrandom(arc4random())
uma vez em qualquer lugar antes de usá-lo para garantir que ele tenha uma semente aleatória diferente para cada execução do seu programa.A resposta do @ jstn é boa, mas um pouco detalhada. O Swift é conhecido como uma linguagem orientada a protocolo, para que possamos obter o mesmo resultado sem precisar implementar o código padrão para todas as classes da família inteira, adicionando uma implementação padrão para a extensão do protocolo.
Agora podemos fazer:
e todas as outras classes inteiras estão ok.
fonte
No Swift 4.2, você pode gerar números aleatórios chamando o
random()
método para qualquer tipo numérico desejado, fornecendo o intervalo com o qual deseja trabalhar. Por exemplo, isso gera um número aleatório no intervalo de 1 a 9, inclusive nos dois ladosTambém com outros tipos
fonte
Aqui está uma biblioteca que faz o trabalho bem https://github.com/thellimist/SwiftRandom
fonte
fonte
Gostaria de acrescentar às respostas existentes que o exemplo de gerador de números aleatórios no livro Swift é um gerador de congruência linear (LCG), é severamente limitado e não deve ser, exceto pelos exemplos triviais, em que a qualidade da aleatoriedade não importa mesmo. E um LCG nunca deve ser usado para fins criptográficos .
arc4random()
é muito melhor e pode ser usado para a maioria dos propósitos, mas novamente não deve ser usado para fins de criptografia.Se você deseja que algo que seja garantido criptograficamente seja seguro, use
SecCopyRandomBytes()
. Observe que, se você criar um gerador de números aleatórios em alguma coisa, outra pessoa poderá acabar (utilizando incorretamente) para fins criptográficos (como senha, chave ou geração de sal), então você deve considerar o uso deSecCopyRandomBytes()
qualquer maneira, mesmo que sua necessidade não seja ' isso exige bastante.fonte
Desde o Swift 4.2
Há um novo conjunto de APIs:
Todos os tipos numéricos agora têm o
random(in:)
método necessáriorange
.Retorna um número uniformemente distribuído nesse intervalo.
TL; DR
Bem, o que há de errado com o "bom" jeito antigo?
Você precisa usar APIs C importadas (elas são diferentes entre plataformas) .
E além disso...
Se você usar
arc4random()
(para calcular o restante) comoarc4random() % aNumber
, o resultado não será distribuído uniformemente entre0
eaNumber
. Há um problema chamado viés do módulo .Viés do módulo
Normalmente, a função gera um número aleatório entre
0
e MAX (depende do tipo etc.) . Para dar um exemplo rápido e fácil, digamos que o número máximo seja7
e você se preocupa com um número aleatório no intervalo0 ..< 2
(ou no intervalo [0, 3), se preferir) .As probabilidades para números individuais são:
Em outras palavras, é mais provável que você termine com 0 ou 1 que 2 . Obviamente, tenha em mente que isso é extremamente simplificado e o número MAX é muito maior, tornando-o mais "justo".
fonte
Sem arc4Random_uniform () em algumas versões do Xcode (na 7.1, ele é executado, mas não é preenchido automaticamente). Você pode fazer isso.
Para gerar um número aleatório de 0 a 5. Primeiro
Então
fonte
Aqui 5 garantirá que o número aleatório seja gerado de zero a quatro. Você pode definir o valor de acordo.
fonte
Swift 4.2
Adeus para importar a Foundation C lib
arc4random_uniform()
More @ oficial
fonte
O código a seguir produzirá um número aleatório seguro entre 0 e 255:
Você chama assim:
Para números maiores, fica mais complicado.
Este é o melhor que eu poderia ter:
Esses métodos usam um número aleatório extra para determinar quantos
UInt8
s serão usados para criar o número aleatório. A última linha converte o[UInt8]
paraUInt16
ouUInt32
.Não sei se os dois últimos ainda contam como verdadeiramente aleatórios, mas você pode ajustá-lo ao seu gosto :)
fonte
Swift 4.2
O Swift 4.2 incluiu uma API de número aleatório nativa e bastante completa na biblioteca padrão. ( Proposta Swift Evolution SE-0202 )
Todos os tipos de números têm o aleatório estático (em :), que pega o intervalo e retorna o número aleatório no determinado intervalo
fonte
Para iOS, macOS e tvOS, você pode usar fonte aleatória em todo o sistema na estrutura do Xcode
GameKit
. Aqui você pode encontrarGKRandomSource
classe com seusharedRandom()
método de classe:Ou apenas use um
randomElement()
método que retorne um elemento aleatório da coleção:fonte
Você pode usar
GeneratorOf
assim:fonte
Eu uso esse código para gerar um número aleatório:
fonte
Detalhes
xCode 9.1, Swift 4
Solução orientada a matemática (1)
Uso da solução (1)
Solução orientada a programadores (2)
Uso da solução (2)
Amostra Completa
Resultado da amostra
fonte