random - 使用 crypto/rand 通过 rand.Perm 生成排列

标签 random go

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 类型的预定义版本?

最佳答案

这基本上就是您需要做的。对于 math/rand 的常见用法,您通常不需要加密安全的随机源,因此没有提供适配器。通过直接在值中分配缓冲区空间,而不是在每次调用时都分配一个新 slice ,您可以使实现稍微高效一些。然而,在读取操作系统随机源失败的不太可能发生的情况下,这将需要 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))
}

关于random - 使用 crypto/rand 通过 rand.Perm 生成排列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40965044/

相关文章:

java - 选择具有双重偏差的随机项目

json - 测试API请求是否正常工作

linux - 查找 [主机] : no such host error in Go

mongodb - 查找时间戳小于 10 秒的所有 mongo db 文档

r - 在 R 中生成多个字符的(随机)序列

python - 随机生成1或-1(正整数或负整数)

c - 优化C语言的一个不重复的随机数代码

java - 以不同的概率随机选择一个对象

go - 如何将值重新分配为 map 输出的空值

arrays - Go - 如何将编码的 json 对象附加到文件