Comment la graine du générateur de nombres aléatoires
Je suis en train de générer une chaîne de caractères aléatoires dans le jeu de Go et voici le code que j'ai écrit jusqu'à présent:
package main
import (
"bytes"
"fmt"
"math/rand"
"time"
)
func main() {
fmt.Println(randomString(10))
}
func randomString(l int) string {
var result bytes.Buffer
var temp string
for i := 0; i < l; {
if string(randInt(65, 90)) != temp {
temp = string(randInt(65, 90))
result.WriteString(temp)
i++
}
}
return result.String()
}
func randInt(min int, max int) int {
rand.Seed(time.Now().UTC().UnixNano())
return min + rand.Intn(max-min)
}
Mon application est très lente. Amorçage à l'aide de time
apporte le même nombre aléatoire pour un certain temps, de sorte itération de la boucle, encore et encore. Comment puis-je améliorer mon code?
- La "si la chaîne(randInt(65,90))!=temp {" il semble que vous essayez d'ajouter une sécurité supplémentaire mais bon, les choses deviennent même un après l'autre par hasard. En faisant cela, vous pouvez effectivement l'abaissement de l'entropie.
- Comme une note de côté, il n'y a pas besoin de se convertir à l'UTC dans "le temps.Maintenant().(UTC).UnixNano()". Le temps Unix est calculé depuis l'Époque qui est UTC de toute façon.
- Vous devez définir la graine une fois, une seule fois, et jamais plus d'une fois. ainsi, dans le cas où votre application s'exécute pendant des jours, vous pouvez l'installer une fois par jour.
- Vous devriez graines une fois. Et je pense que le "Z" ne peut jamais apparaître, je suppose? Donc, je préfère utiliser les index de début inclusive et à la fin de l'index exclusif.
Vous devez vous connecter pour publier un commentaire.
Chaque fois que vous définissez une même semence, vous obtenez la même séquence. Alors bien sûr, si vous êtes à la définition de la graine à la fois dans une boucle rapide, vous aurez sûrement l'appeler avec la même graine de nombreuses fois.
Dans votre cas, que vous appelez votre
randInt
fonction jusqu'à ce que vous avez une valeur différente, vous êtes en attente pour le moment (retourné par Nano) à changer.Comme pour tous les pseudo-aléatoire bibliothèques, vous devez définir la graine qu'une seule fois, par exemple lors de l'initialisation de votre programme, sauf si vous avez spécifiquement besoin de reproduire une séquence donnée (ce qui est généralement fait uniquement pour le débogage et les tests unitaires).
Après cela, il vous suffit d'appeler
Intn
pour obtenir le prochain nombre entier aléatoire.Déplacer le
rand.Seed(time.Now().UTC().UnixNano())
ligne à partir de la fonction randInt le début de la principale, et tout sera plus rapide.Remarque aussi que je pense que vous pouvez simplifier votre chaîne de bâtiment:
rand.Seed(...)
à la fonctioninit()
.init()
est appelée automatiquement avantmain()
. Notez que vous n'avez pas besoin d'appelerinit()
demain()
!return min + rand.Intn(max - min + 1)
crypto/rand
doit être utilisé.Je ne comprends pas pourquoi les gens sont de semis avec une valeur de temps. Ce qui a mon expérience jamais été une bonne idée. Par exemple, alors que l'horloge système est peut-être représenté en nanosecondes, le système de l'horloge de précision n'est pas nanosecondes.
Ce programme ne doit pas être exécutée sur le pouce de terrain de jeu, mais si vous l'exécutez sur votre machine, vous obtenez une estimation approximative sur ce type de précision vous pouvez vous attendre. Je vois incréments d'environ 1000000 ns, donc 1 ms par incréments. C'est sur 20 bits d'entropie qui ne sont pas utilisés. Tous le tandis que les bits élevés sont souvent constant.
Le degré que ce qui compte pour vous varient, mais vous pouvez éviter les pièges de l'horloge à base de graines de valeurs en utilisant simplement la
crypto/rand.Read
comme source de semences. Il vous donnera non-déterministe de la qualité que vous êtes probablement à la recherche dans votre nombres aléatoires (même si la mise en œuvre effective elle-même est limité à un ensemble de différentes séquences aléatoires et déterministes).Comme une note de côté, mais par rapport à votre question. Vous pouvez créer votre propre
rand.Source
à l'aide de cette méthode pour éviter le coût d'avoir des verrous de protection de la source. Lerand
package utilitaire fonctions sont pratiques, mais ils utilisent aussi des serrures sous le capot pour empêcher la source de l'être utilisé en même temps. Si vous n'en avez pas besoin, vous pouvez l'éviter en créant votre propreSource
et de l'utiliser dans un non-simultanées façon. Peu importe, vous ne devriez PAS être le réensemencement de votre générateur de nombre aléatoire entre les itérations, il n'a jamais été conçu pour être utilisé de cette façon.juste à jeter pour la postérité: il peut parfois être préférable de générer une chaîne de caractères aléatoires en utilisant un premier jeu de caractères chaîne de caractères. Ceci est utile si la chaîne est censé être saisies manuellement par l'homme; à l'exclusion de 0, O, 1, et l peuvent aider à réduire l'erreur de l'utilisateur.
et en général, je mis la graine à l'intérieur d'un
init()
bloc. Ils sont documentés ici: http://golang.org/doc/effective_go.html#init-1
dansrand.Intn(len(alpha)-1)
. C'est parce querand.Intn(n)
renvoie toujours un nombre qui est inférieur àn
(en d'autres mots: de zéro àn-1
inclus).-1
danslen(alpha)-1
aurait garanti que le numéro 9 n'a jamais été utilisé dans la séquence.OK pourquoi si complexe!
C'est en fonction de la dystroy du code, mais équipée pour mes besoins.
C'est mourir six (rands ints
1 =< i =< 6
)La fonction ci-dessus est exactement la même chose.
J'espère que cette information a été en usage.
3 5 2 5 4 2 5 6 3 1
rand.Intn()
, sinon vous obtiendrez toujours le même nombre chaque fois que vous exécutez votre programme.var bytes int
? Quelle est la différence à l'évolution de la ci-dessusbytes = rand.Intn(6)+1
àbytes := rand.Intn(6)+1
? Ils semblent tous deux à travailler pour moi, est l'un d'entre eux sous-optimale pour une raison quelconque?C'est nano secondes, quelles sont les chances d'obtenir les mêmes graines deux fois.
De toute façon, merci pour l'aide, voici ma solution basée sur toutes les entrées.
what are the chances of getting the exact the exact same [nanosecond] twice?
Excellent. Tout dépend de la précision interne de la mise de la golang runtimes. Même si les parts sont des nano-secondes, le plus petit incrément d'une milli-seconde ou même une seconde.Si votre but est simplement de créer une piqûre de nombre aléatoire puis je pense que c'est inutile de compliquer avec de multiples appels de fonction ou la réinitialisation de semences à chaque fois.
L'étape la plus importante est l'appel de la graine de la fonction juste une fois avant l'exécution de
rand.Init(x)
. De la graine utilise la condition de semences de valeur pour initialiser la Source par défaut pour un déterministe de l'état. Donc, Il est suggéré de l'appeler une fois avant l'appel à la fonction générateur de nombres pseudo aléatoires.Voici un exemple de code permettant de créer une chaîne de nombres aléatoires
La raison, j'ai utilisé Sprintf est parce qu'il permet la mise en forme de chaîne.
Aussi, Dans
rand.Intn(7)
Intn renvoie, comme un int, un non-négative du nombre pseudo-aléatoire dans [0,7).Petite mise à jour en raison de golang api changement, veuillez omettre .(UTC) :
temps.Maintenant().UTC().UnixNano() -> temps.Maintenant().UnixNano()