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

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

Using crypto/rand for generating permutations with rand.Perm

问题

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

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

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

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

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

package main

import (
	cryptoRand "crypto/rand"
	"encoding/binary"
	"fmt"
	mathRand "math/rand"
)

type cryptoSource struct{}

func (s cryptoSource) Int63() int64 {
	bytes := make([]byte, 8, 8)
	cryptoRand.Read(bytes)
	return int64(binary.BigEndian.Uint64(bytes) >> 1)
}

func (s cryptoSource) Seed(seed int64) {
	panic("seed")
}

func main() {
	rnd := mathRand.New(&cryptoSource{})
	perm := rnd.Perm(52)
	fmt.Println(perm)
}

这段代码是有效的。理想情况下,我不想自己定义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:

package main

import (
	cryptoRand "crypto/rand"
	"encoding/binary"
	"fmt"
	mathRand "math/rand"
)
    
type cryptoSource struct{}

func (s cryptoSource) Int63() int64 {
	bytes := make([]byte, 8, 8)
	cryptoRand.Read(bytes)
	return int64(binary.BigEndian.Uint64(bytes) >> 1)
}

func (s cryptoSource) Seed(seed int64) {
	panic("seed")
}

func main() {
    rnd := mathRand.New(&cryptoSource{})
    perm := rnd.Perm(52)
	fmt.Println(perm)
}

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 来防止返回无效的结果。

type cryptoSource [8]byte

func (s *cryptoSource) Int63() int64 {
    _, err := cryptoRand.Read(s[:])
    if err != nil {
        panic(err)
    }
    return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
}
英文:

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.

type cryptoSource [8]byte

func (s *cryptoSource) Int63() int64 {
	_, err := cryptoRand.Read(s[:])
	if err != nil {
	    panic(err)
    }
	return int64(binary.BigEndian.Uint64(s[:]) &amp; (1&lt;&lt;63 - 1))
}

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:

确定