GoLang 中的隨機數 tips

隨機數咱們都知道,就是計算機經過某種算法,「隨機」的生成一個數字。不少編程語言都有內置的方法來生成隨機數,那麼 GoLang 中是怎樣一種狀況呢?git

僞隨機數

咱們都知道「隨機數」在現實生活中的概念,可能你隨手拋一個硬幣,就能夠說其結果是隨機的,可是在計算機中要肯定一個「隨機數」真的是「隨機數」,那但是有標準的,不是你隨隨便便說是就是。github

根據密碼學原理,要想對一個「隨機數」進行隨機性檢驗有如下幾個標準:golang

  • 統計學僞隨機性 - 在給定的隨機比特流樣本中,1 的數量大體等於 0 的數量,也就是說,「10」「01」「00」「11」 四者數量大體相等。說人話就是:「一眼看上去是隨機的」。
  • 密碼學安全僞隨機性 - 就是給定隨機樣本的一部分和隨機算法,不能有效的演算出隨機樣本的剩餘部分。
  • 真隨機性 - 其定義爲隨機樣本不可重現。

根據以上幾個標準,其對應的隨機數也就分爲如下幾類:算法

  • 僞隨機數 - 知足第一個條件的隨機數。
  • 密碼學安全的僞隨機數 - 同時知足前兩個條件的隨機數。能夠經過密碼學安全僞隨機數生成器計算得出。
  • 真隨機數 -同時知足三個條件的隨機數。

瞭解了以上幾個概念,咱們就知道了「僞隨機數」其實就是一個「看似隨機,實則並不真正隨機」的數字。編程

僞隨機數生成器

在實際應用中大部分狀況下僞隨機數就足夠了。這些數列是「彷佛」隨機的數,實際上它們是經過一個固定的、能夠重複的計算方法產生的。由於它們其實是能夠計算出來的,因此它們並不真正地隨機,可是它們具備相似於隨機數的統計特徵。產生這樣的結果的生成器咱們叫作僞隨機數生成器。安全

通常只有在密碼學場景中,咱們才須要使用「真隨機數」。dom

在大部分編程語言中,提供的都是「僞隨機數生成器」,例如 JS 中的 Math.random()GoLang 中的 math/rand 包。編程語言

GoLang 中的僞隨機數

GoLang 中,咱們能夠經過 math/rand 包裏的方法來生成一個僞隨機數:函數

package main

import (
  "fmt"
  "math/rand"
)

func main() {
  fmt.Println(rand.Int())   // => 134020434
}
複製代碼

上面的代碼中,咱們經過 rand.Int() 方法來生成一個僞隨機數。看起來好像沒什麼問題嘛,人家也很 OK 啦。google

可是細心的你會發現,你在本身電腦上運行上面的代碼居然和個人同樣。不管你怎麼運行,它都同樣。

咱們知道 JS 中的 Math.random() 每次都會返回一個不同的數字,可是 GoLang 中的僞隨機數生成器默認狀況下居然會返回相同的數值,這還不反了天了?

都是僞隨機數生成器,爲何差異就這麼大呢?這裏咱們就要了解一下「隨機種子」的概念啦。

隨機種子

咱們知道,僞隨機數,是使用一個肯定性的算法計算出來的彷佛是隨機的數序,所以僞隨機數實際上並不隨機。

那麼天然,在計算僞隨機數時假如使用的開始值不變的話,那麼算法計算出的僞隨機數的數序天然也是不變的咯。

這個「開始值」,就被稱爲隨機種子。

查閱文檔,咱們得知,Int() 函數是從 default Source(默認源)中產生的僞隨機數。

而這個 default Source,咱們從 Seed 部分能夠看到,若是你沒有設置隨機種子,那麼默認初始種子老是從 1 開始。

既然隨機種子同樣,那天然其結果也是同樣的。

隨機的僞隨機數

咱們已經知道了默認隨機種子是從 1 開始,那麼咱們只要在每次生成隨機數以前先設置一個不同的種子,那麼其結果天然也就不同了。

咱們要儘量保證每次僞隨機數生成器工做時使用的是不一樣的種子,一般的作法是採用當前時間做爲種子。

package main

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

func main() {
  rand.Seed(int64(time.Now().UnixNano()))

  fmt.Println(rand.Int())
}
複製代碼

這樣,因爲種子不一樣,咱們每次運行的結果也就不同。咱們就能達到獲取僞隨機數的目的啦。

真隨機數

若是咱們的應用對安全性要求比較高,須要使用真隨機數的話,那麼可使用 crypto/rand 包中的方法。

package main

import (
  "crypto/rand"
  "fmt"
  "math/big"
)

func main() {
  // 生成 20 個 [0, 100) 範圍的真隨機數。
  for i := 0; i < 20; i++ {
    result, _ := rand.Int(rand.Reader, big.NewInt(100))
    fmt.Println(result)
  }
}
複製代碼

上面的程序每次運行的結果都是不同的,會真正隨機的生成隨機數。


訪問 github.com/sqrthree/sq… 閱讀更多文章。

相關文章
相關標籤/搜索