go math/rand包详解

package rand

import "math/rand"

rand包实现了伪随机数生成器。

math_rand go官方标准文档

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

在go中生成随机数需要一个结构体实例 Rand ,要构建这个结构体需要一些参数;为了便捷,go已经在math/rand包中定义好了一个Rand结构体实例,只需要调用Rand的一些方法就可以生成各种随机数来。下面简单认识一下Rand结构体:

type Rand struct {
	src Source
	s64 Source64 // 如果src为空,则为64

	// readVal包含用于字节的63位整数的remainer,在最近的读取调用期间生成。
	//  它被保存,以便下一个读调用可以从上一个读调用结束的地方开始。 
	readVal int64

	//  readPos表示仍然有效的readVal的低位字节数。 
	readPos int8
}

简单示例:

package main
 
import (
	"fmt"
	"math/rand"
)
 
func main() {
	// 调用rand的方法生成伪随机int值
	fmt.Println(rand.Int())
	fmt.Println(rand.Int31())
	fmt.Println(rand.Intn(5))
}

运行结果:

5577006791947779410
2019727887
2

当代码运行多次发现时,结果都是一样的。不管怎么运行代码,产生的结果都是这三个数,不会变。为什么?这是因为我们还没有设置随机数种子。

rand.Seed 设置随机数种子

func (r *Rand) Seed(seed int64) 使用给定的seed来初始化生成器到一个确定的状态。

修改后的代码:

package main

import (
	"fmt"
	"math/rand"
	"time"
)

func main()  {
	rand.Seed(time.Now().UnixNano()) // 取纳秒时间戳,可以保证每次的随机数种子都不同
	fmt.Println(rand.Int())
	fmt.Println(rand.Int31())
	fmt.Println(rand.Intn(5))
}

代码多次运行,就会发现每次结果是不一样的

7684945739848266880
1210528256
4
-------------------
4700552700982711365
1927716820
4

自定义生成Rand结构体,设置随机数种子

除了上面生成伪随机数的方法,我们还可以自定义生成Rand结构体,本质上与Rand提供好的结构体没有太大区别,下面简单介绍下自己声明Rand结构体,来生成伪随机数:

func NewSource(seed int64) Source
使用给定的种子创建一个伪随机资源。

func New(src Source) *Rand
返回一个使用src生产的随机数来生成其他各种分布的随机数值的*Rand。

代码示例:

package main
 
import (
	"fmt"
	"math/rand"
	"time"
)
 
func main() {
	source := rand.NewSource(time.Now().UnixNano()) // 使用当前的纳秒生成一个随机源,也就是随机种子
	ran := rand.New(source) // 生成一个rand
	fmt.Println(rand.Int())
	fmt.Println(rand.Int31())
	fmt.Println(rand.Intn(5))
}

这两种方法本质上没有区别,NewSource()方法等价于前面的rand.Seed()方法,都是用来设置随机种子。

其它生成随机数的方法

Rand生成随机数当然不只这三个方法,还有其它生成随机数的方法

func (r *Rand) Int63() int64
返回一个int64类型的非负的63位伪随机数。

func (r *Rand) Uint32() uint32
返回一个uint32类型的非负的32位伪随机数。

func Int31n(n int32) int32
返回一个取值范围在[0,n)的伪随机int32值,如果n<=0会panic。

func Int63n(n int64) int64
返回一个取值范围在[0, n)的伪随机int64值,如果n<=0会panic。

func (r *Rand) Float32() float32
返回一个取值范围在[0.0, 1.0)的伪随机float32值。

func (r *Rand) Float64() float64
返回一个取值范围在[0.0, 1.0)的伪随机float64值。

func (r *Rand) Perm(n int) []int
返回一个有n个元素的,[0,n)范围内整数的伪随机排列的切片。

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() {
    for i := 0; i < 10; i++ {
        fmt.Printf("%.4d ", rand.Int31()%10000)
    }
}

运行结果:

8081 7887 1847 4059 2081 1318 4425 2540 0456 3300

go crypto/rand

package rand

import "crypto/rand"

rand包实现了用于加解密的更安全的随机数生成器,主要应用场景:生成随机加密串

crypto_rand go官方标准文档

主要方法
(1)func Int(rand io.Reader, max *big.Int) (n *big.Int, err error)

返回一个在[0, max)区间服从均匀分布的随机值,如果max<=0则会panic

(2)func Prime(rand io.Reader, bits int) (p *big.Int, err error)

返回一个具有指定字位数(二进制的位数)的数字,该数字具有很高可能性是质数。如果从rand读取时出错,或者bits<2会返回错误

(3)func Read(b []byte) (n int, err error)

本函数是一个使用io.ReadFull调用Reader.Read的辅助性函数。当且仅当err == nil时,返回值n == len(b)
代码示例:

package main
 
import (
    "crypto/rand"
    "encoding/base64"
    "fmt"
    "math/big"
)
 
func main() {
    //1、Int
    n, err := rand.Int(rand.Reader, big.NewInt(128))
    if err == nil {
        fmt.Println("rand.Int:", n, n.BitLen())
    }
    //2、Prime
    p, err := rand.Prime(rand.Reader, 5)
    if err == nil {
        fmt.Println("rand.Prime:", p)
    }
    //3、Read
    b := make([]byte, 32)
    m, err := rand.Read(b)
    if err == nil {
        fmt.Println("rand.Read:", b[:m])
        fmt.Println("rand.Read:", base64.URLEncoding.EncodeToString(b))
    }
}

运行结果:

    rand.Int: 92 7
    rand.Prime: 29
    rand.Read: [207 47 241 208 190 84 109 134 86 106 87 223 111 113 203 155 44 118 71 20 186 62 66 130 244 98 97 184 8 179 6 230]
    rand.Read: zy_x0L5UbYZWalffb3HLmyx2RxS6PkKC9GJhuAizBuY=

常用的是 func Read(b []byte) (n int, err error) 这个方法, 将随机的byte值填充到b 数组中,以供b使用。示例如下:

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)
}

运行结果:

[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
[68 221 145 73 115 224 13 110 218 130 19 139 38 170 145 58 251 188 126 197]

相关推荐:

python 如何使用math模块

math模块提供常用数学函数和常量,不支持复数;需importmath后通过math.调用,如math.sqrt(16)返回4.0;常用函数包括sqrt、pow、ceil、floor、round等。 Python的math模块提供了大量常用的数学函数和常量,适用于科学计算、工程运算等场景。它不支持复...

js中Math对象指的是什么

js中Math对象指的是什么?这个问题可能是我们日常学习或工作经常见到的。希望通过这个问题能让你收获颇深。下面是小编给大家带来的参考内容,让我们一起来看看吧!1.Math对象的属性  (1)E:返回算术常量e,即自然对数的底数(约等于2.718)。  (2)LN2:返回2的自然对数(约等于0.693...

ES6如何新增math,Number方法

这篇文章将为大家详细讲解有关ES6如何新增math,Number方法,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。Nunber.isInteger()判断是否为整数,需要注意的是1,和1.0都会被认为是整数console.log(Number.isInteger(...

Java中如何使用Math类

这篇文章将为大家详细讲解有关Java中如何使用Math类,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。Java常用类库Math类Math包含用于执行基本数字运算的方法,例如基本指数,对数,平方根和三角函数一、FieldSummaryModifiera...

Go语言标准库math和rand的常用函数有哪些

本篇内容介绍了“Go语言标准库math和rand的常用函数有哪些”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!math标准库math标准库提供了一些常量如int64类型的最大值、float64类型的最...

js中的Math方法怎么使用

这篇“js中的Math方法怎么使用”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“js中的Math方法怎么使用”文章吧。1.min()和max()方法Math.min()用于确定一组数值...

怎么JavaScript中使用Math数学

这期内容当中小编将会给大家带来有关怎么JavaScript中使用Math数学,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。具体如下://Math是全局的   //Math.PI 数学里的3.1415926....   console....

C++的math函数如何用

今天小编给大家分享一下C++的math函数如何用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。包含头文件#include<cmath>1、fabs(doublex)对dou...