1. 程式人生 > 實用技巧 >go math/rand包詳解

go math/rand包詳解

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)範圍內整數的偽隨機排列的切片。