golang学习笔记 ---rand
在Golang中,有两个包提供了rand,分别为 "math/rand" 和 "crypto/rand", 对应两种应用场景。
- "math/rand" 包实现了伪随机数生成器。也就是生成 整形和浮点型。 该包中根据生成伪随机数是是否有种子(可以理解为初始化伪随机数),可以分为两类:
- 有种子。通常以时钟,输入输出等特殊节点作为参数,初始化。该类型生成的随机数相比无种子时重复概率较低。
- 无种子。可以理解为此时种子为1, Seek(1)
golang 随机数有一个很有趣的地方,如果我们不自行定义随机数种子的话,每次生成的随机数都是一样的。golang 在默认随机的时候,固定以数字 1 作为种子。既然种子都固定了的话,那每次执行的结果当然是一样的。比如 第二个for
循环,打印 10 个随机数,每次运行结果是一模一样的。
要解决这个问题,就需要以时间作为随机数种子。如第一个for循环:
package main import ( "fmt" "math/rand" "time" ) func main() {
//以时间为随机种子 for i := 0; i < 10; i++ r := rand.New(rand.NewSource(time.Now().UnixNano())) fmt.Printf("%d ", r.Int31()) } fmt.Println(" ")
//无种子,其实是固定以1为种子 for i := 0; i < 10; i++ { fmt.Printf("%d ", rand.Int31()) } }
输出:
第一次运行结果
276310213 276310213 276310213 939632684 939632684 939632684 939632684 939632684 939632684 939632684
1298498081 2019727887 1427131847 939984059 911902081 1474941318 140954425 336122540 208240456 646203300
第二次运行结果
1101837366 1101837366 1101837366 1101837366 1101837366 1101837366 1101837366 1101837366 1101837366 1101837366
1298498081 2019727887 1427131847 939984059 911902081 1474941318 140954425 336122540 208240456 646203300
第三次运行结果
483465292 483465292 483465292 483465292 1406725908 1406725908 1406725908 1406725908 1406725908 1406725908
1298498081 2019727887 1427131847 939984059 911902081 1474941318 140954425 336122540 208240456 646203300
常用的方法有:(以有种子的为例,无种子的直接通过 rand 调用对应的方法)
1> 按类型随机类: func (r *Rand) Int() int func (r *Rand) Int31() int32 func (r *Rand) Int63() int64 func (r *Rand) Uint32() uint32 func (r *Rand) Float32() float32 // 返回一个取值范围在[0.0, 1.0)的伪随机float32值 func (r *Rand) Float64() float64 // 返回一个取值范围在[0.0, 1.0)的伪随机float64值 2>指定随机范围类: func (r *Rand) Intn(n int) int func (r *Rand) Int31n(n int32) int32 func (r *Rand) Int63n(n int64) int64
拓展:对于需要随机指定位数的,当位数不够是,可以通过前边补0达到长度一致,如
package main import ( "fmt" "math/rand" ) func main() { // 随机产生6位长度伪随机数 for i := 0; i < 10; i++ { fmt.Printf("%.6d ", rand.Int31()%1000000) } }
输出
498081 727887 131847 984059 902081 941318 954425 122540 240456 203300
package main import ( "fmt" "math/rand" "time" ) func init() { //以时间作为初始化种子 rand.Seed(time.Now().UnixNano()) } func main() { a := rand.Int() fmt.Println(a) b := rand.Intn(100) fmt.Println(b) c := rand.Float32() fmt.Println(c) }
输出:
1910927962 45 0.9863281
”crypto/rand“ 包实现了用于加解密的更安全的随机数生成器:该包中常用的是 func Read(b []byte) (n int, err error) 这个方法, 将随机的byte值填充到b 数组中,以供b使用。示例如下:
package main import ( "crypto/rand" "fmt" ) func main() { b := make([]byte, 20) fmt.Println(b) // _, err := rand.Read(b) if err != nil { fmt.Println(err.Error()) } fmt.Println(b) }
几点注意项:
1、如果不使用rand.Seed(seed int64),每次运行,得到的随机数会一样,程序不停止,一直获取的随机数是不一样的;
2、每次运行时rand.Seed(seed int64),seed的值要不一样,这样生成的随机数才会和上次运行时生成的随机数不一样;
3、rand.Intn(n int)得到的随机数int i,0 <= i < n。