在Go中生成随机数

huangapple go评论139阅读模式
英文:

Generating Random Numbers in Go

问题

我正在尝试在Go中生成随机数(整数),但一直没有成功。我在crypto/rand中找到了rand包,看起来是我想要的,但是从文档中我无法确定如何使用它。这是我现在尝试的代码:

  1. b := []byte{}
  2. something, err := rand.Read(b)
  3. fmt.Printf("something = %v\n", something)
  4. fmt.Printf("err = %v\n", err)

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

  1. something = 0
  2. err = <nil>

有没有办法修复这个问题,使其实际生成随机数?或者,有没有办法设置生成的随机数的上限?

英文:

I am trying to generate random numbers (integers) in Go, to no avail. I found the rand package in crypto/rand, which seems to be what I want, but I can't tell from the documentation how to use it. This is what I'm trying right now:

  1. b := []byte{}
  2. something, err := rand.Read(b)
  3. fmt.Printf(&quot;something = %v\n&quot;, something)
  4. fmt.Printf(&quot;err = %v\n&quot;, err)

But unfortunately this always outputs:

  1. something = 0
  2. err = &lt;nil&gt;

Is there a way to fix this so that it actually generates random numbers? Alternatively, is there a way to set the upper bound on the random numbers this generates?

答案1

得分: 28

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

这是经典的“使用当前时间作为种子生成一个数字”的程序:

  1. package main
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "time"
  6. )
  7. func main() {
  8. rand.Seed(time.Now().Unix())
  9. fmt.Println(rand.Int())
  10. }
英文:

Depending on your use case, another option is the math/rand package. Don't do this if you're generating numbers that need to be completely unpredictable. It can be helpful if you need to get results that are reproducible, though -- just pass in the same seed you passed in the first time.

Here's the classic "seed the generator with the current time and generate a number" program:

  1. package main
  2. import (
  3. &quot;fmt&quot;
  4. &quot;math/rand&quot;
  5. &quot;time&quot;
  6. )
  7. func main() {
  8. rand.Seed(time.Now().Unix())
  9. fmt.Println(rand.Int())
  10. }

答案2

得分: 27

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

  1. package main
  2. import "encoding/binary"
  3. import "crypto/rand"
  4. func main() {
  5. var n int32
  6. binary.Read(rand.Reader, binary.LittleEndian, &n)
  7. println(n)
  8. }
英文:

crypto/rand provides only binary stream of random data, but you can read integers from it using encoding/binary:

  1. package main
  2. import &quot;encoding/binary&quot;
  3. import &quot;crypto/rand&quot;
  4. func main() {
  5. var n int32
  6. binary.Read(rand.Reader, binary.LittleEndian, &amp;n)
  7. println(n)
  8. }

答案3

得分: 17

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

<code><pre>
package main

import "fmt"
import "time"
import "math/rand"

func main() {
rand.Seed(time.Now().UnixNano()) // 以纳秒为种子获取当前时间
fmt.Println(rand.Intn(100)) // 这将给您一个小于100的整数
}
</pre></code>

英文:

As of 1 april 2012, after the release of the stable version of the lang, you can do the following:

<code><pre>
package main

import "fmt"
import "time"
import "math/rand"

func main() {
rand.Seed(time.Now().UnixNano()) // takes the current time in nanoseconds as the seed
fmt.Println(rand.Intn(100)) // this gives you an int up to but not including 100
}
</pre></code>

答案4

得分: 0

你还可以开发自己的随机数生成器,可以基于一个简单的“荒岛伪随机数生成器”——线性同余生成器。此外,还可以查阅L'Ecuyer(1999)、Mersenne Twister或Tausworthe生成器。

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

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

  1. package pmPRNG
  2. import "errors"
  3. const (
  4. Mersenne31 = 2147483647 // = 2^31-1
  5. Mersenne31Inv = 1.0 / 2147483647.0 // = 4.656612875e-10
  6. // a = 16807
  7. a = 48271
  8. )
  9. // 每个流都有自己的种子
  10. type PRNGStream struct {
  11. state int
  12. }
  13. func PRNGStreamNew(seed int) *PRNGStream {
  14. prng := (&PRNGStream{})
  15. prng.SetSeed(seed)
  16. return prng
  17. }
  18. // 强制种子在[1, 2^31-1]范围内
  19. func (r *PRNGStream) SetSeed(seed int) error {
  20. var err error
  21. if seed < 1 || seed > Mersenne31 {
  22. err = errors.New("Seed OOB")
  23. }
  24. if seed > Mersenne31 {
  25. seed = seed % Mersenne31
  26. }
  27. if seed < 1 {
  28. seed = 1
  29. }
  30. r.state = seed
  31. return err
  32. }
  33. // Dig = Park-Miller DesertIslandGenerator
  34. // 整数种子在[1, 2^31-1]范围内
  35. func (r *PRNGStream) Dig(seed int) float32 {
  36. xprev := r.state // x[i-1]
  37. xnext := (a * xprev) % Mersenne31 // x[i] = (a*x[i-1])%m
  38. r.state = xnext // x[i-1] = x[i]
  39. Ri := float32(xnext) * Mersenne31Inv // 将Ui转换为Ri
  40. return Ri
  41. }
  42. func (r *PRNGStream) Rand() float32 {
  43. r.state = (uint64_t)*r.state * Multby % 0x7fffffff
  44. return float32(r.state) * Mersenne31Inv
  45. }

一些相关链接:

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

您可以使用此函数来更新x[i+1],而不是上面的函数,
val = ((state * 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://learn.microsoft.com/en-us/archive/msdn-magazine/2016/august/test-run-lightweight-random-number-generation

英文:

You can also develop your own random number generator, perhaps based upon a simple "desert island PRNG", a Linear Congruential Generator. Also, look up L'Ecuyer (1999), Mersenne Twister, or Tausworthe generator...

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

(Avoid RANDU, it was popular in the 1960's, but the random numbers generated fall on 15 hyperplanes in 3-space).

  1. package pmPRNG
  2. import &quot;errors&quot;
  3. const (
  4. Mersenne31 = 2147483647 // = 2^31-1
  5. Mersenne31Inv = 1.0 / 2147483647.0 // = 4.656612875e-10
  6. // a = 16807
  7. a = 48271
  8. )
  9. // Each stream gets own seed
  10. type PRNGStream struct {
  11. state int
  12. }
  13. func PRNGStreamNew(seed int) *PRNGStream {
  14. prng := (&amp;PRNGStream{})
  15. prng.SetSeed(seed)
  16. return prng
  17. }
  18. // enforce seed in [1, 2^31-1]
  19. func (r*PRNGStream) SetSeed(seed int) error {
  20. var err error
  21. if seed &lt; 1 || seed &gt; Mersenne31 {
  22. err = errors.New(&quot;Seed OOB&quot;)
  23. }
  24. if seed &gt; Mersenne31 { seed = seed % Mersenne31 }
  25. if seed &lt; 1 { seed = 1 }
  26. r.state = seed
  27. return err
  28. }
  29. // Dig = Park-Miller DesertIslandGenerator
  30. // integer seed in [1, 2^31-1]
  31. func (r*PRNGStream) Dig(seed int) float32 {
  32. xprev := r.state // x[i-1]
  33. xnext := (a * xprev) % Mersenne31 // x[i] = (a*x[i-1])%m
  34. r.state = xnext // x[i-1] = x[i]
  35. Ri := float32(xnext) * Mersenne31Inv // convert Ui to Ri
  36. return Ri
  37. }
  38. func (r*PRNGStream) Rand() float32 {
  39. r.state = (uint64_t)*r.state * Multby % 0x7fffffff
  40. return float32(r.state) * Mersenne31Inv
  41. }

A few relevant links:

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

You might use this function to update your x[i+1], instead of the one above,
val = ((state * 1103515245) + 12345) & 0x7fffffff
(basically, different values of 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://learn.microsoft.com/en-us/archive/msdn-magazine/2016/august/test-run-lightweight-random-number-generation

huangapple
  • 本文由 发表于 2011年5月31日 06:29:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/6181260.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定