博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
golang中的随机数rand
阅读量:3987 次
发布时间:2019-05-24

本文共 3489 字,大约阅读时间需要 11 分钟。

随机数从资源生成。包水平的函数都使用的默认的公共资源。

该资源会在程序每次运行时都产生确定的序列。如果需要每次运行产生不同的序列,应使用Seed函数进行初始化。默认资源可以安全的用于多go程并发。

关于种子seed

程序启动的时候,种子的初始值是一样的,也就是说随机数是一样的,什么意思呢?

package mainimport (   "fmt"   "math/rand")func main(){
data := rand.Int63n(100) fmt.Println(data)}

每次运行go run main.go

打印的都是 10

如果我们播放种子

package mainimport (   "fmt"   "math/rand"   "time")func main(){
rand.Seed(time.Now().Unix()) // unix 时间戳,秒 data := rand.Int63n(100) fmt.Println(data)}

这样每次执行go run main.go

打印的结果就不一样,但是,根据随机数的特性,如果两次执行的时间戳是在同一秒,那么打印的结果是相同的。
以上的随机数相同的情况是发生在程序启动的时候,如果程序启动后,每次生成随机数会怎样呢?

package mainimport (   "fmt"   "math/rand")func main(){
for i := 0; i<5; i++ {
data := rand.Int63n(100) fmt.Println(data) }}

运行 go run main.go

打印
10
51
21
51
37

再次运行 go run main.go

打印
10
51
21
51
37

可见每次启动的结果是一样的;但是程序启动后,每次的随机数都不尽相同,是随机的。

如果再加上种子呢?

package mainimport (   "fmt"   "math/rand"   "time")func main(){
for i := 0; i<5; i++ {
rand.Seed(time.Now().Unix()) // unix 时间戳,秒 data := rand.Int63n(100) fmt.Println(data) }}

运行 go run main.go

打印
86
86
86
86
86

再次运行 go run main.go

打印
72
72
72
72
72

每次启动程序,因为种子不一样,所以随机数不一样;但是程序启动后,每次也都是播放种子,秒级时间戳,如果时间戳一样,就导致种子一样,生成的随机数就一样,所以五次的随机数是一样的。

通过上面的例子。可以知道,播放种子不是必须的,除非要求每次启动程序的时候随机数不一样。

并且,要设置种子的情况下,应该放在整个程序启动的时候,而且只需要设置一次即可。修改上面的例子:

package mainimport (   "fmt"   "math/rand"   "time")func main(){
rand.Seed(time.Now().UnixNano()) // 纳秒时间戳 for i := 0; i<5; i++ {
data := rand.Int63n(100) fmt.Println(data) }}

运行 go run main.go

打印
3
49
46
83
25

再次运行 go run main.go

打印
39
3
14
42
65

这次就是理想的结果了。使用纳秒时间戳基本就没问题了,因为我们的程序几乎不会在1纳秒时间内多次启动的。

下面来讲讲rand包的具体用法

rand 包提供了两块的内容,一块是基于 Rand 结构体及其方法;另一块是基于 Rand 结构体再封装的可直接调用的方法 rand.xxx,查看源码就知道它们是同样的功能。

所以,生成随机数有两种方式

rander := rand.New(rand.NewSource(time.Now().UnixNano()))n1 := rander.Intn(100)rand.Seed(time.Now().UnixNano())n2 := rand.Intn(100)

使用第一种方法,将 rander 作为包的全局变量,这样就只会设置一次种子。

var Rander = rand.New(rand.NewSource(time.Now().UnixNano()))

随机整数

func (r *Rand) Int() intfunc (r *Rand) Int31() int32func (r *Rand) Int63() int64func (r *Rand) Uint32() uint32func (r *Rand) Uint64() uint64func (r *Rand) Intn(n int) intfunc (r *Rand) Int31n(n int32) int32func (r *Rand) Int63n(n int64) int64

Int, Int31, Int63 生成的数都太大,一般使用 Intn, Int31n, Int63n。得到的范围 [0, n),想要得到 [0, n],就要使用 Intn(n + 1),想要得到 [10, 100] 的随机数,就要使用 Intn(91) + 10。

随机浮点数

func (r *Rand) Float32() float32func (r *Rand) Float64() float64

得到 [0, 1) 之间的浮点数,32单精度,64双精度。

基于正态分布的随机浮点数

func (r *Rand) NormFloat64() float64

基于指数分布的随机浮点数

func (r *Rand) ExpFloat64() float64

随机序列

func (r *Rand) Perm(n int) []int

返回一个有n个元素的,[0,n)范围内整数的伪随机排列的切片。

Rander.Perm(10) // [1 8 0 4 7 6 3 2 9 5]

总结:

package mainimport (	"fmt"	"math/rand"	"strings"	"time")func main() {
s := RandString(10) fmt.Println(s)}var Rander = rand.New(rand.NewSource(time.Now().UnixNano()))const letterString = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"const numLetterString = "0123456789"// 随机生成字符串func RandStr(n int, letter string) string {
str := []byte(letter) res := "" for i := 0; i < n; i++ {
res += fmt.Sprintf("%c", str[Rander.Intn(strings.Count(letter, "") - 1)]) } return res}func RandNumStr(n int) string {
return RandStr(n, numLetterString)}func RandString(n int) string {
return RandStr(n, letterString)}func RandOrder(n int) string {
return time.Now().Format("20060102150405") + RandNumStr(n)}// 包含min, maxfunc RandNum(min , max int) int {
return Rander.Intn(max - min + 1) + min}

转载地址:http://ecaui.baihongyu.com/

你可能感兴趣的文章
Jlink + ADS调试 S3C2440
查看>>
2440初始化存储器原理(接上一篇)
查看>>
S3C2440 USB 设备控制器(转)
查看>>
Linux usb 设备驱动 (1)
查看>>
Linux usb设备驱动(2)---> usbmouse.c 源码分析
查看>>
USB芯片
查看>>
ajax工作原理
查看>>
理解Sharding jdbc原理,看这一篇就够了
查看>>
XiaoMi面试题记录
查看>>
解决跨网场景下,CAS重定向无法登录的问题(无需修改现有代码)
查看>>
java反编译命令
查看>>
activemq依赖包获取
查看>>
版本号中Snapshot的含义
查看>>
JAVA 成员访问权限修饰符
查看>>
Centos下Mysql密码忘记解决办法
查看>>
概念区别
查看>>
关于静态块、静态属性、构造块、构造方法的执行顺序
查看>>
final 的作用
查看>>
在Idea中使用Eclipse编译器
查看>>
idea讲web项目部署到tomcat,热部署
查看>>