在 Go 中生成随机数

Posted

技术标签:

【中文标题】在 Go 中生成随机数【英文标题】:Generating Random Numbers in Go 【发布时间】:2011-09-05 02:13:54 【问题描述】:

我试图(整数),但无济于事。我在crypto/rand 中找到了rand 包,这似乎是我想要的,但我无法从文档中得知如何使用它。这就是我现在正在尝试的:

    b := []byte
    something, err := rand.Read(b)
    fmt.Printf("something = %v\n", something)
    fmt.Printf("err = %v\n", err)

但不幸的是,这总是输出:

    something = 0
    err = <nil>

有没有办法解决这个问题,以便它实际生成随机数?或者,有没有办法设置生成的随机数的上限?

【问题讨论】:

我希望该例程用随机字节填充数组b,无论您要求多少。 我也是 - 我刚接触 Go,不熟悉调用约定等。 它将填充 b 但是 b 是一个空切片(并且后备数组的大小为 0)。所以 rand.Read() 没有空间来存储任何东西,并在您的 something 变量中返回 0,这表明没有存储任何内容。 b := make([]byte,4) 会更合适,允许 rand.Read 在 b 中存储 4 个字节 已经很晚了,但对于其他读者RanGo module 可能会有所帮助,其灵感来自this answer 【参考方案1】:

根据您的用例,另一个选项是math/rand 包。如果您要生成需要完全不可预测的数字,请不要这样做。但是,如果您需要获得可重复的结果,这会很有帮助 - 只需传递您第一次传递的同一个种子。

这是经典的“以当前时间为生成器播种并生成一个数字”程序:

package main

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

func main() 
    rand.Seed(time.Now().Unix())
    fmt.Println(rand.Int())

【讨论】:

【参考方案2】:

crypto/rand 仅提供随机数据的二进制流,但您可以使用 encoding/binary 从中读取整数:

package main

import "encoding/binary"
import "crypto/rand"

func main() 
    var n int32
    binary.Read(rand.Reader, binary.LittleEndian, &n)
    println(n)

【讨论】:

我在操场上试过这个,结果总是一样:play.golang.org/p/Bh-f4QEyKf @Karlom 输出由该站点缓存。它不会再次重新运行相同的程序。【参考方案3】:

截至 2012 年 4 月 1 日,在稳定版 lang 发布后,您可以执行以下操作:

package main

导入“fmt” 导入“时间” 导入“数学/兰德”

函数 main() rand.Seed(time.Now().UnixNano()) // 以纳秒为单位的当前时间作为种子 fmt.Println(rand.Intn(100)) // 这给你一个 int 最多但不包括 100

【讨论】:

这几乎是我在询问伪随机数时所期望的。 time.Now().Unix() 不像 UnixNano() 那样完全够用。【参考方案4】:

您还可以开发自己的随机数生成器,可能基于简单的“沙漠岛 PRNG”,即线性同余生成器。另外,查找 L'Ecuyer (1999)、Mersenne Twister 或 Tausworthe 生成器...

https://en.wikipedia.org/wiki/Pseudorandom_number_generator

(避免使用 RANDU,它在 1960 年代很流行,但生成的随机数落在 3 空间中的 15 个超平面上)。

package pmPRNG

import "errors"

const (
    Mersenne31 = 2147483647 // = 2^31-1
    Mersenne31Inv = 1.0 / 2147483647.0 // = 4.656612875e-10

    // a = 16807
    a = 48271
)

// Each stream gets own seed
type PRNGStream struct 
    state int


func PRNGStreamNew(seed int) *PRNGStream 
    prng := (&PRNGStream)
    prng.SetSeed(seed)
    return prng


// enforce seed in [1, 2^31-1]
func (r*PRNGStream) SetSeed(seed int) error 
    var err error

    if seed < 1 || seed > Mersenne31 
        err = errors.New("Seed OOB")
    

    if seed > Mersenne31  seed = seed % Mersenne31 
    if seed < 1  seed = 1 
    r.state = seed

    return err


// Dig = Park-Miller DesertIslandGenerator
// integer seed in [1, 2^31-1]
func (r*PRNGStream) Dig(seed int) float32 
    xprev := r.state // x[i-1]
    xnext := (a * xprev) % Mersenne31 // x[i] = (a*x[i-1])%m
    r.state = xnext // x[i-1] = x[i]
    Ri := float32(xnext) * Mersenne31Inv // convert Ui to Ri
    return Ri



func (r*PRNGStream) Rand() float32 
    r.state = (uint64_t)*r.state * Multby % 0x7fffffff
    return float32(r.state) * Mersenne31Inv

一些相关链接:

https://en.wikipedia.org/wiki/Lehmer_random_number_generator

你可以使用这个函数来更新你的 x[i+1],而不是上面那个, val = ((状态 * 1103515245) + 12345) & 0x7fffffff (基本上a、c、m的值不同)

https://www.redhat.com/en/blog/understanding-random-number-generators-and-their-limitations-linux

https://www.iro.umontreal.ca/~lecuyer/myftp/papers/handstat.pdf

https://www.math.utah.edu/~alfeld/Random/Random.html

https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/august/test-run-lightweight-random-number-generation

【讨论】:

以上是关于在 Go 中生成随机数的主要内容,如果未能解决你的问题,请参考以下文章

在 Go 语言中生成固定长度的随机数

在 pyCuda 内核中生成单个随机数

如何在 Bash 中生成随机数?

在 Dart 中生成唯一的随机数

如何在 django 中生成随机数

如何在Javascript中生成随机数[重复]