Golang中math/rand与crypto/rand的区别解析
Golang中math/rand与crypto/rand的区别解析 大家好!
首先感谢所有花时间阅读这篇文章的人。 我是Go语言的新手,刚刚发现了两个随机数生成包,并对它们之间的差异感到着迷。
非常感谢Saito San。这非常有帮助。 我查看了随机数生成器列表 没有关于LFG的评论。 我想了解LFG和Mersenne Twister的比较。 因为我计划使用Mersenne Twister(MT)或更好的算法。 有谁知道MT是否比LFG更好? Steve
这个讨论非常有启发性,但对于像我一样刚接触Go语言的人来说,真正看到随机数生成器的随机性表现可能会很有趣。
我写的小程序基本上是我尝试理解Rob Pike的fan-in模式。 Rob Pike的代码在这里:Go Playground - The Go Programming Language
我写了一个类似的程序,其中一个生成器生成1到6之间的随机数,模拟掷骰子。 两个这样的生成器同时启动,然后一个收集器goroutine将每个生成器的计数相加。
这个例子使用了math/rand:
Go Playground - The Go Programming Language
而这个例子使用了crypto/rand:
Go Playground - The Go Programming Language
第一个例子在所有10次掷骰中可能只有2种可能的结果,通常只有1种! 第二个更符合我对掷骰子的预期。有时A赢,有时B赢。
所以,我学到的是:每当我需要数字是随机的,比如在任何游戏中,我需要使用crypto/rand。
我的理解有误吗? 也非常欢迎对代码的任何评论。
谢谢, Raphael
更多关于Golang中math/rand与crypto/rand的区别解析的实战教程也可以访问 https://www.itying.com/category-94-b0.html
又一个好方法!非常感谢!!
非常巧妙
更多关于Golang中math/rand与crypto/rand的区别解析的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
感谢戈麦斯先生。
非常感谢!
明白了!感谢提供宝贵信息!
通常在游戏开始时这样做:
rand.Seed(time.Now().UnixNano())
在我的电脑上运行正常。这一定是 Go Playground 的某些特性造成的。
真有意思。
我尝试了这种方法,至少在 Go Playground 中,种子值在几分钟内保持不变。 请看这里: https://play.golang.org/p/jGi7LjzFUQC
啊!非常感谢! 那是不是要用 rand.Seed(seed int64) 方法? 但在游戏中我该怎么做呢? 我得找个种子来源…
确实如此,在 Go 语言游乐场中时间是固定的,正如此处所解释的:
在游乐场中,时间起始于 2009-11-10 23:00:00 UTC(确定这个日期的意义留给读者作为练习)。通过提供确定性输出,这使得缓存程序变得更加容易。
关于这个主题的更多信息:
官方的 ioutil.TempFile 函数(参见 https://golang.org/src/io/ioutil/tempfile.go)用于创建具有随机名称的临时文件,它使用了简单的《数值食谱》方法,并使用 time.Now().UnixNano() + int64(os.Getpid()) 作为种子。
func main() {
fmt.Println("hello world")
}
raphbaph:
因此,我了解到的是:每当我在任何游戏中需要随机数时,都需要使用 crypto/rand。
我的理解有误吗?
你没有注意到可以为 math/rand 包更改种子值来生成不同的数字序列,同时也可以作为生成器的源。 math 包中的随机数生成器使用某些已知算法生成伪随机数,而 crypto 包中的随机数生成器在可能的情况下会使用真正的随机源。但后者的代价要高得多。
在我看来,math/rand 包可以用于简单的游戏,但在需要真正随机性的场景下则不适用。
// 代码示例:使用 math/rand 生成随机数
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
rand.Seed(time.Now().UnixNano())
fmt.Println("随机数:", rand.Intn(100))
}
在Go语言中,math/rand和crypto/rand是两个用于生成随机数的包,但它们在设计目标、随机性质量和适用场景上有本质区别。你的测试结果正确反映了这一点:math/rand生成伪随机数,适合非安全场景,而crypto/rand提供密码学安全的随机数,适用于安全敏感应用。以下是对两个包的详细解析和代码示例。
1. math/rand:伪随机数生成器
- 原理:基于确定性算法(如线性同余生成器)生成序列,初始种子相同则输出序列相同。
- 性能:速度快,资源开销低。
- 随机性:适用于模拟、测试、游戏等非安全场景,但随机性可预测。
- 示例代码:
package main
import (
"fmt"
"math/rand"
"time"
)
func main() {
// 使用时间作为种子,确保每次运行结果不同
rand.Seed(time.Now().UnixNano())
fmt.Println("掷骰子结果:", rand.Intn(6) + 1) // 生成1到6的随机数
}
2. crypto/rand:密码学安全随机数生成器
- 原理:从操作系统获取熵源(如硬件噪声),生成不可预测的随机数。
- 性能:速度较慢,资源开销较高。
- 随机性:适用于密钥生成、令牌、加密等安全敏感场景。
- 示例代码:
package main
import (
"crypto/rand"
"encoding/binary"
"fmt"
)
func main() {
var n int32
// 读取随机字节并解码为int32
binary.Read(rand.Reader, binary.BigEndian, &n)
if n < 0 {
n = -n // 确保非负
}
fmt.Println("掷骰子结果:", (n % 6) + 1) // 生成1到6的随机数
}
关键区别总结
| 特性 | math/rand | crypto/rand |
|---|---|---|
| 随机性质量 | 伪随机,可预测 | 密码学安全,不可预测 |
| 性能 | 高 | 低 |
| 适用场景 | 游戏、模拟、测试 | 加密、认证、安全令牌 |
| 种子依赖 | 需显式设置种子 | 自动从系统熵源获取 |
针对你的代码分析
- 在第一个示例(使用
math/rand)中,由于未设置种子或种子固定,导致输出序列重复,这在伪随机数生成中是典型行为。 - 第二个示例(使用
crypto/rand)利用了系统熵源,结果更接近真实随机分布,符合掷骰子的预期。
因此,你的理解正确:在需要不可预测随机性的场景(如游戏输赢判定),应使用crypto/rand。对于非关键用途(如测试数据生成),math/rand更高效。根据需求选择包是Go开发中的标准实践。

