2015年10月20日火曜日

Go langでrandを使って擬似乱数を作る

Go langで擬似乱数を作ってみます。
簡単なコードとしては以下のようになります。
0から9までの数字を10回出力します。
package main

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

func main() {
    rand.Seed(time.Now().UnixNano())
    for i := 0; i < 10; i++ {
        fmt.Println("My favorite number is", rand.Intn(10))
    }
}
$ go run rand.go
My favorite number is 0
My favorite number is 7
My favorite number is 0
My favorite number is 8
My favorite number is 3
My favorite number is 3
My favorite number is 7
My favorite number is 5
My favorite number is 0
My favorite number is 8
rand.Seed(time.Now().UnixNano()) という箇所で乱数の元になるシードを与えるのがポイントです。
なぜ、シードを与えるかというと、ここで使っている関数rand.Intnは、randパッケージに新しい乱数ジェネレータ生成するときに同じ初期化 rand.NewSource(1) をしているそうで、シードをあたえて、異なる乱数を出す必用があるからだそうです。

以下、シードを与えていないと、同じ結果になる例です。
func main() {
    // シードを与えないで実行
    for i := 0; i < 10; i++ {
        fmt.Print(rand.Intn(10), " ")
    }
    fmt.Println(" ")

    // randをNewSourceで初期化して実行
    my_rand := rand.New(rand.NewSource(1))
    for i := 0; i < 10; i++ {
        fmt.Print(my_rand.Intn(10), " ")
    }
    fmt.Println(" ")

    // シードを与えて実行
    my_rand.Seed(time.Now().UnixNano())
    for i := 0; i < 10; i++ {
        fmt.Print(my_rand.Intn(10), " ")
    }
}
$ go run rand.go
1 7 7 9 1 8 5 0 6 0
1 7 7 9 1 8 5 0 6 0
8 7 1 0 1 4 9 0 3 0
$ go run rand.go
1 7 7 9 1 8 5 0 6 0
1 7 7 9 1 8 5 0 6 0
4 0 4 7 2 0 2 9 7 0

乱数を使って抽選を実装したlotteryという面白いライブラリを作っている方がいたので、遊んでみました。
go get実行を実行してgithubのコードを取得。
$ go get github.com/kyokomi/lottery
$ tree ~/gocode/src/github.com/
/Users/yako/gocode/src/github.com/
└── kyokomi
    └── lottery
        ├── LICENSE
        ├── README.md
        ├── circle.yml
        ├── lottery.go
        └── lottery_test.go

2 directories, 5 files
1/5の確率でアタリ、それ以外をハズレとして、1000回出力。アタリが出た確率も最後に出力します。
package main

import (
        "fmt"
        "github.com/kyokomi/lottery"
        "math/rand"
        "time"
)

func main() {
        lot := lottery.New(rand.New(rand.NewSource(time.Now().UnixNano())))

        check := 1000
        count := 0

        for i := 0; i < check; i++ {

                if lot.LotOf(1, 5) {
                        // 1/5の確率
                        fmt.Print("アタリ")
                        count++
                } else {
                        fmt.Print("ハズレ")
                }

        }

        fmt.Println(float32(count)/float32(check)*100, "%")

}
$ go run lottery.go
ハズレハズレハズレアタリアタリアタリハズレハズレハズレアタリハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレハズレアタリハズレアタリハズレハズレハズレハズレアタリハズレハズレアタリハズレアタリハズレアタリハズレハズレアタリアタリハズレアタリハズレハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレアタリアタリハズレハズレハズレアタリハズレハズレアタリアタリハズレハズレハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレアタリハズレアタリハズレハズレハズレアタリハズレハズレハズレハズレハズレアタリアタリハズレアタリハズレハズレハズレハズレハズレハズレハズレハズレハズレハズレアタリアタリハズレアタリハズレハズレハズレハズレハズレハズレアタリアタリハズレハズレハズレハズレアタリハズレハズレアタリ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19.9 %
抽選プログラムを作る機会があったら使ってみるとよさそうです。

参考文献)
rand - The Go Programming Language
https://golang.org/pkg/math/rand/
お気楽 Go 言語プログラミング入門 並列プログラミング
Goでlotteryという抽選ライブラリを作った - きょこみのーと
http://kyokomi.hatenablog.com/entry/2015/07/26/151138

Top image from Anthony Starks Gopher inspecting Go code
The Go gopher was designed by Renee French. http://reneefrench.blogspot.com/