使用crypto / rand生成rand.Perm的排列

时间:2016-12-04 23:36:52

标签: random go

Go有两个随机数的包:

  • crypto/rand,它提供了获取随机字节的方法
  • math/rand,它有一个很好的改组整数算法

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

由于两个rand包是同一标准库的一部分,因此应该有一种方法以某种方式组合它们,以便crypto/rand提供math/rand.Perm使用的随机数的良好来源。 1}}生成排列。

这里(以及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类型的预定义版本是什么?

1 个答案:

答案 0 :(得分:2)

这基本上就是你需要做的。对于math/rand的常见用法,您通常不需要加密安全的随机源,因此没有提供适配器。通过直接在结构中分配缓冲区空间,而不是在每次调用时分配新的切片,可以使实现略微提高效率。

type cryptoSource struct {
    buf [8]byte
}

func (s *cryptoSource) Int63() int64 {
    cryptoRand.Read(s.buf[:])
    return int64(binary.BigEndian.Uint64(s.buf[:]) & (1<<63 - 1))
}

或者只是将源[8]byte本身设为

type cryptoSource [8]byte

func (s *cryptoSource) Int63() int64 {
    cryptoRand.Read(s[:])
    return int64(binary.BigEndian.Uint64(s[:]) & (1<<63 - 1))
}