使用crypto/rand和rand.Perm生成排列。

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

Using crypto/rand for generating permutations with rand.Perm

问题

Go语言有两个用于生成随机数的包:

  • crypto/rand,提供了获取随机字节的方法
  • math/rand,具有一个用于对整数进行洗牌的好算法

我想使用math/rand中的Perm算法,但是要提供高质量的随机数。

由于这两个rand包都是标准库的一部分,应该有一种方法将它们结合起来,使得crypto/rand提供一个好的随机数源,供math/rand.Perm用于生成排列。

这里是我编写的连接这两个包的代码(在Playground上也有):

  1. package main
  2. import (
  3. cryptoRand "crypto/rand"
  4. "encoding/binary"
  5. "fmt"
  6. mathRand "math/rand"
  7. )
  8. type cryptoSource struct{}
  9. func (s cryptoSource) Int63() int64 {
  10. bytes := make([]byte, 8, 8)
  11. cryptoRand.Read(bytes)
  12. return int64(binary.BigEndian.Uint64(bytes) >> 1)
  13. }
  14. func (s cryptoSource) Seed(seed int64) {
  15. panic("seed")
  16. }
  17. func main() {
  18. rnd := mathRand.New(&cryptoSource{})
  19. perm := rnd.Perm(52)
  20. fmt.Println(perm)
  21. }

这段代码是有效的。理想情况下,我不想自己定义cryptoSource类型,而是将这两个rand包组合在一起,使它们能够一起工作。所以是否有一个预定义版本的cryptoSource类型存在?

英文:

Go has two packages for random numbers:

  • crypto/rand, which provides a way to get random bytes
  • math/rand, which has a nice algorithm for shuffling ints

I want to use the Perm algorithm from math/rand, but provide it with high-quality random numbers.

Since the two rand packages are part of the same standard library there should be a way to combine them in a way so that crypto/rand provides a good source of random numbers that is used by math/rand.Perm to generate a permutation.

Here (and on the Playground) is the code I wrote to connect these two packages:

  1. package main
  2. import (
  3. cryptoRand "crypto/rand"
  4. "encoding/binary"
  5. "fmt"
  6. mathRand "math/rand"
  7. )
  8. type cryptoSource struct{}
  9. func (s cryptoSource) Int63() int64 {
  10. bytes := make([]byte, 8, 8)
  11. cryptoRand.Read(bytes)
  12. return int64(binary.BigEndian.Uint64(bytes) >> 1)
  13. }
  14. func (s cryptoSource) Seed(seed int64) {
  15. panic("seed")
  16. }
  17. func main() {
  18. rnd := mathRand.New(&cryptoSource{})
  19. perm := rnd.Perm(52)
  20. fmt.Println(perm)
  21. }

This code works. Ideally I don't want to define the cryptoSource type myself but just stick together the two rand packages so that they work together. So is there a predefined version of this cryptoSource type somewhere?

答案1

得分: 3

这基本上是你需要做的。通常情况下,对于math/rand的常规用法,你不经常需要一个加密安全的随机源,所以没有提供适配器。你可以通过直接在值中分配缓冲区空间,而不是在每次调用时分配新的切片,使实现稍微更高效。然而,如果读取操作系统的随机源失败,这将需要引发 panic 来防止返回无效的结果。

  1. type cryptoSource [8]byte
  2. func (s *cryptoSource) Int63() int64 {
  3. _, err := cryptoRand.Read(s[:])
  4. if err != nil {
  5. panic(err)
  6. }
  7. return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
  8. }
英文:

That's basically what you need to do. It's not often that you need a cryptographically secure source of randomness for the common usage of math/rand, so there's no adaptor provided. You can make the implementation slightly more efficient by allocating the buffer space directly in the value, rather than allocating a new slice on every call. However in the unlikely event that reading the OS random source fails, this will need to panic to prevent returning invalid results.

  1. type cryptoSource [8]byte
  2. func (s *cryptoSource) Int63() int64 {
  3. _, err := cryptoRand.Read(s[:])
  4. if err != nil {
  5. panic(err)
  6. }
  7. return int64(binary.BigEndian.Uint64(s[:]) &amp; (1&lt;&lt;63 - 1))
  8. }

huangapple
  • 本文由 发表于 2016年12月5日 07:36:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/40965044.html
匿名

发表评论

匿名网友

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

确定