プログラミング
記事内に商品プロモーションを含む場合があります

Go言語で乱数のシードを設定する方法|rand.Seedは非推奨

tadanori

Go1.20からrand.Seed()で乱数を初期化するのは非推奨となったようです。この記事では、大体手段のrand.New(rand.NewSource(seed))の使い方を説明します

rand.Seedでワーニング

VSCodeでrand.Seed()で以下のようなワーニングが出るようになりました。

一番上に書かれている行を抜粋したのが以下になります。

rand.Seed is deprecated: As of Go 1.20 there is no reason to call Seed with a random value. Programs that call Seed with a known value to get a specific sequence of results should use New(NewSource(seed)) to obtain a local random generator.

これを読むと、Go1.20からSeedを呼ぶのではなく、New(NewSource(seed))を使うようにということらしいです。

ということで、rand.Seed()を使わない方法を紹介します。

rand.New(NewSource(Seed))を使った乱数発生

rand.New(rand.NewSource(seed))では、乱数ジェネレータを作成して乱数を発生させます。以下、seedを設定する場合と、time関数で設定する方法の2つを紹介します。

seedを設定する場合

rand.Newで乱数ジェネレータを作成し、作成したジェネレータを使って乱数を発生させます(r.Intnの部分)

package main

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

func main() {
	var r *rand.Rand
	r = rand.New(rand.NewSource(42))

	fmt.Println(r.Intn(10))
}

time関数を利用して乱数を発生させる場合

time関数をSeedに使う場合は、以下のようにします。

package main

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

func main() {
	var r *rand.Rand
	r = rand.New(rand.NewSource(time.Now().UnixNano()))

	fmt.Println(r.Intn(10))
}

Goのrand.Randの関数の一覧

以下、rand.Randで発生できる乱数の一覧(関数一覧)です。

関数名説明
Float32()半開区間 [0.0,1.0) の擬似乱数を float32 として返す
Float64()半開区間 [0.0,1.0) の擬似乱数を float64 として返す
Int()負でない疑似乱数 int を返す
Intn(n int)半開区間 [0,n) の非負の擬似乱数を int として返す
Int31()非負の擬似ランダム 31 ビット整数を int32 として返す
Int31n(n int32)半開区間 [0,n) の非負の擬似乱数を int32 として返す
Int63()負でない疑似ランダム 63 ビット整数を int64 として返す
Int63n(n int64)半開区間 [0,n) の非負の擬似乱数を int64 として返す
NormFloat64()標準正規分布 (平均 = 0、標準偏差 = 1) で、-math.MaxFloat64 から +math.MaxFloat64 までの範囲の正規分布した float64 を返す
Perm(n int)n 個の整数のスライスとして、半開区間 [0,n) の整数の擬似ランダム順列を返す
Shuffle(n int, swap func(i, j int))要素の順序を擬似ランダム化する
Uint32()疑似ランダム 32 ビット値を uint32 として返す
Uint64()疑似ランダム 64 ビット値を uint64 として返す

Shuffleが結構面白いので、少し紹介します。

Go言語のrand.Shuffleの使い方

Shuffleの定義は、Shuffle(n int, swap func(i, j int))となっていて、配列などを渡す部分がありません。どうやって使うかというと、以下のようになります。

func()の部分に、処理を書く形です。

package main

import (
	"fmt"
	"math/rand"
)

func main() {
	var r *rand.Rand
	r = rand.New(rand.NewSource(42))

	const N = 10
	a := make([]int, 0)
	for i := 0; i < N; i++ {
		a = append(a, i)
	}
	fmt.Println(a)
	// [0 1 2 3 4 5 6 7 8 9]

	r.Shuffle(N, func(i, j int) {
		a[i], a[j] = a[j], a[i]
	})

	fmt.Println(a)
	// [2 5 7 9 6 8 1 4 0 3]
}

わかりにくいですが、応用が効きます。例えば5~9まで(5以上の値)をシャッフルしたくない場合は、以下のように記述すれば実現できます。

	r.Shuffle(N, func(i, j int) {
		if i < 5 && j < 5 {
			a[i], a[j] = a[j], a[i]
		}
	})

	fmt.Println(a)
	// [2 0 4 3 1 5 6 7 8 9]

if文により5未満しか置換されないため、結果として0~4まではシャッフルされ、5以上はシャッフルされません。

応用範囲は広いと思います

まとめ

VSCodeでrand.Seedでワーニングが出たので、ワーニングの理由と代替手段について調べてみましたので紹介しました。

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

記事URLをコピーしました