Golang随机数发生器如何正确种子(Golang random number generator

2019-06-27 23:26发布

我想产生转到一个随机字符串,这里是到目前为止,我写的代码:

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

我的实现是很慢的。 采用播种time一次又一次带来了一定的时间相同的随机数,所以循环迭代。 我怎样才能提高我的代码?

Answer 1:

每次设置相同的种子时,你会得到相同的序列。 所以,当然,如果你设置种子的时间在一个快速循环,你可能会使用相同的种子多次调用它。

在你的情况,因为你打电话你randInt功能,直到你有不同的值,你等待的时间(由纳米返回)改变。

对于所有的伪随机图书馆 ,你有你的初始化程序时,除非特别需要再现给定序列(通常仅用于调试和单元测试完成)设置种子仅一次,例如。

之后,你只需调用Intn得到一个随机整数。

移动rand.Seed(time.Now().UTC().UnixNano())从randInt功能线到主的开始,一切都将更快。

还需要注意的是,我认为可以简化您的字符串建筑:

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


Answer 2:

只是抛它出去后代:它有时可以是优选的,以产生使用初始字符集串的随机串。 如果该字符串应该是由人手动输入这是有用的; 不含0,O,1,和L可以帮助减少用户错误。

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

我通常设置内部的种子init()块。 他们要在这里记载: http://golang.org/doc/effective_go.html#init



Answer 3:

OK,为什么这么复杂!

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

这是基于关闭dystroy的代码,但装我的需求。

这是死六(兰特整数1 =< i =< 6

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

上面的功能是完全一样的事情。

我希望这个信息是使用。



Answer 4:

我不明白为什么人们有时间值播种。 这在我的经验,从来就不是一个好主意。 例如,当系统时钟在纳秒也许代表了系统的时钟精度不纳秒。

这个程序不应该转到操场上运行,但如果你在你的机器上运行它,你会得到你可以期望什么类型的精度的粗略估计。 我看到的100多万纳秒,所以1周毫秒为单位递增。 这一点用都没有熵的20位。 一直以来高位大多是不变的。

这对你很可能会有所不同,但你可以通过简单地使用基于避免时钟种子值的缺陷程度crypto/rand.Read源为您的种子。 它会给你,你很可能希望在您的随机数(即使实际的实现本身是有限的一组独特的和确定性随机序列)不确定性的质量。

import (
    crypto_rand "crypto/rand"
    "encoding/binary"
    math_rand "math/rand"
)

func init() {
    var b [8]byte
    _, err := crypto_rand.Read(b[:])
    if err != nil {
        panic("cannot seed math/rand package with cryptographically secure random number generator")
    }
    math_rand.Seed(int64(binary.LittleEndian.Uint64(b[:])))
}

作为一个方面说明,但相对于你的问题。 你可以创建自己的rand.Source使用这种方法,以避免锁保护源的成本。 的rand包效用函数是便利的,但它们也使用锁罩下以防止源被同时使用。 如果你不需要,你可以通过创建自己的避免它Source和使用,在非同步的方式。 无论如何,你不应该进行补种迭代之间的随机数发生器,它从未被设计用来这种方式。



Answer 5:

这是纳米秒,什么都得到相同的种子两次的机会。
无论如何,感谢您的帮助,这里是一个基于所有输入我的最终解决方案。

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


Answer 6:

如果你的目标只是产生随机数的刺痛话,我认为这是没有必要将其与多个函数调用或重置种子每次复杂化。

最重要的一步是实际运行之前调用函数的种子只有一次rand.Init(x) 种子使用所提供的种子值来初始化缺省源来确定的状态。 因此,这将是建议的实际函数调用伪随机数生成器之前调用它一次。

下面是一个示例代码创建一个随机数串

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



func main(){
    rand.Seed(time.Now().UnixNano())

    var s string
    for i:=0;i<10;i++{
    s+=fmt.Sprintf("%d ",rand.Intn(7))
    }
    fmt.Printf(s)
}

我使用的原因sprintf的是,因为它允许简单的字符串格式化。

另外,在rand.Intn(7) 内置内置返回,作为int,在[0,7)一个非负的伪随机数。



文章来源: Golang random number generator how to seed properly
标签: random go