Pregunta Generador de números aleatorios de Golang cómo sembrar adecuadamente


Estoy intentando generar una cadena aleatoria en Ir y aquí está el código que he escrito hasta ahora:

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

Mi implementación es muy lenta. Sembrando usando time trae el mismo número aleatorio para un cierto tiempo, por lo que el ciclo itera una y otra vez. ¿Cómo puedo mejorar mi código?


113
2017-09-07 15:29


origen


Respuestas:


Cada vez que establece la misma semilla, obtiene la misma secuencia. Entonces, por supuesto, si está estableciendo la semilla al tiempo en un bucle rápido, probablemente lo llame con la misma semilla muchas veces.

En tu caso, cuando llamas a tu randInt función hasta que tenga un valor diferente, está esperando que cambie el tiempo (según lo devuelto por Nano).

Como para todas las bibliotecas pseudoaleatorias, debe establecer la semilla solo una vez, por ejemplo, al inicializar su programa a menos que necesite reproducir específicamente una secuencia determinada (que generalmente solo se realiza para la depuración y la prueba de unidades).

Después de eso, simplemente llame Intn para obtener el siguiente entero aleatorio.

Mueve el rand.Seed(time.Now().UTC().UnixNano()) línea desde la función randInt hasta el inicio de la principal y todo será más rápido.

Tenga en cuenta también que creo que puede simplificar la construcción de cadenas:

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

169
2017-09-07 15:33



solo para arrojarlo a la posteridad: a veces puede ser preferible generar una cadena aleatoria usando una cadena de conjunto de caracteres inicial. Esto es útil si se supone que un humano debe ingresar la cadena manualmente; excluyendo 0, O, 1 yl puede ayudar a reducir el error del usuario.

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

y normalmente pongo la semilla dentro de un init() bloquear. Están documentados aquí: http://golang.org/doc/effective_go.html#init


14
2017-09-07 17:09



OK por qué tan complejo!

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

Esto se basa en el código de la distroy pero se ajusta a mis necesidades.

Son los seis (rands ints 1 =< i =< 6)

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

La función anterior es exactamente la misma.

Espero que esta información sea útil.


11
2017-10-20 11:23



Son nano segundos, ¿cuáles son las posibilidades de obtener la misma semilla dos veces?
De todos modos, gracias por la ayuda, esta es mi solución final basada en toda la información.

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
2017-09-11 09:53