Golang générateur de nombres aléatoires comment semer correctement

J'essaie de générer une chaîne aléatoire dans 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 implémentation est très lente. L'ensemencement en utilisant time apporte le même nombre aléatoire pendant un certain temps, de sorte que la boucle itère encore et encore. Comment puis-je améliorer mon code?

116
demandé sur copperMan 2012-09-07 19:29:44

4 réponses

Chaque fois que vous définissez la même graine, vous obtenez la même séquence. Donc, bien sûr, si vous définissez la graine à l'heure dans une boucle rapide, vous l'appellerez probablement avec la même graine plusieurs fois.

Dans votre cas, comme vous appelez votre Fonction randInt jusqu'à ce que vous ayez une valeur différente, vous attendez que l'heure (renvoyée par Nano) change.

Comme pour toutes les bibliothèques pseudo-aléatoires , vous ne devez définir la graine qu'une seule fois, par exemple lors de l'initialisation de votre programme, sauf si vous 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, vous appelez simplement Intn pour obtenir le prochain entier aléatoire.

Déplacez la ligne rand.Seed(time.Now().UTC().UnixNano()) de la fonction randInt au début de la main et tout sera plus rapide.

Notez également que je pense que vous pouvez simplifier votre construction de chaînes:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UTC().UnixNano())
    fmt.Println(randomString(10))
}

func randomString(l int) string {
    bytes := make([]byte, l)
    for i := 0; i < l; i++ {
        bytes[i] = byte(randInt(65, 90))
    }
    return string(bytes)
}

func randInt(min int, max int) int {
    return min + rand.Intn(max-min)
}
172
répondu Denys Séguret 2018-05-29 08:24:23

Juste pour le jeter pour la postérité: il peut parfois être préférable de générer une chaîne aléatoire en utilisant une chaîne de jeu de caractères initiale. Ceci est utile si la chaîne est supposée être entrée manuellement par un humain; l'exclusion de 0, O, 1 et l peut aider à réduire les erreurs de l'utilisateur.

var alpha = "abcdefghijkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789"

// generates a random string of fixed size
func srand(size int) string {
    buf := make([]byte, size)
    for i := 0; i < size; i++ {
        buf[i] = alpha[rand.Intn(len(alpha))]
    }
    return string(buf)
}

Et je règle généralement la graine à l'intérieur d'un bloc init(). Ils sont documentés ici: http://golang.org/doc/effective_go.html#init

14
répondu jorelli 2013-04-08 06:36:07

OK pourquoi si complexe!

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed( time.Now().UnixNano())
    var bytes int

    for i:= 0 ; i < 10 ; i++{ 
        bytes = rand.Intn(6)+1
        fmt.Println(bytes)
        }
    //fmt.Println(time.Now().UnixNano())
}

Ceci est basé sur le code de dystroy mais adapté à mes besoins.

, C'est à mourir de six (rands ints 1 =< i =< 6)

func randomInt (min int , max int  ) int {
    var bytes int
    bytes = min + rand.Intn(max)
    return int(bytes)
}

La fonction ci-dessus est exactement la même chose.

J'espère que cette information a été utile.

12
répondu Luviz 2012-10-22 04:05:55

C'est nano secondes, quelles sont les chances d'obtenir la même graine deux fois.
De toute façon, merci pour l'aide, voici ma solution basée sur toutes les entrées.

package main

import (
    "math/rand"
    "time"
)

func init() {
    rand.Seed(time.Now().UTC().UnixNano())
}

// generates a random string
func srand(min, max int, readable bool) string {

    var length int
    var char string

    if min < max {
        length = min + rand.Intn(max-min)
    } else {
        length = min
    }

    if readable == false {
        char = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
    } else {
        char = "ABCDEFHJLMNQRTUVWXYZabcefghijkmnopqrtuvwxyz23479"
    }

    buf := make([]byte, length)
    for i := 0; i < length; i++ {
        buf[i] = char[rand.Intn(len(char)-1)]
    }
    return string(buf)
}

// For testing only
func main() {
    println(srand(5, 5, true))
    println(srand(5, 5, true))
    println(srand(5, 5, true))
    println(srand(5, 5, false))
    println(srand(5, 7, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 10, false))
    println(srand(5, 50, true))
    println(srand(5, 4, true))
    println(srand(5, 400, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
    println(srand(6, 5, true))
}
0
répondu RoboTamer 2012-09-11 09:53:43