在go中生成一个随机bool

时间:2017-07-11 09:30:52

标签: go random boolean

在go中产生随机bool的最快方法是什么?

目前我这样做:

package main

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

// random generator
var src = rand.NewSource(time.Now().UnixNano())
var r = rand.New(src)

func main() {
    for i := 0; i < 100; i++ {
        // generate a random boolean and print it 
        fmt.Printf("bool: %s\n", r.Intn(2) != 0)
    }
}

我该如何改进?

4 个答案:

答案 0 :(得分:4)

我只是一个菜鸟,但这对我来说比提供的其他解决方案更有意义:

package randbool

import (
    "math/rand"
    "time"
)

/*
RandBool
    This function returns a random boolean value based on the current time
*/
func RandBool() bool {
    rand.Seed(time.Now().UnixNano())
    return rand.Intn(2) == 1
}

尽管我对go不太熟悉,所以请原谅我的格式。

我最初认为可能像Python中那样有一个return value if condition else other value表达式,但是我找不到找到这种方法的方法。如果有办法,请在评论中告知我。

安全地呆在那里,并洗手。

答案 1 :(得分:3)

如何生成随机bool值的示例可以在这里找到(不一定是最快的解决方案,因为那里没有要求):

How can I let a function randomly return either a true or a false in go

此类算法中最慢的部分始终是获取随机数据(随机信息)。例如,rand.Int31()调用返回31个随机位,但是如果我们只使用它来生成&#34;随机bool值(1位信息),我们浪费30位(可能是30个额外的随机bool值!)。

使用rand.Source是一个不错的选择,因为我们不需要所有的代码功夫&#34; rand.Rand对随机数据执行的操作。我们只需要一个随机信息来源。

rand.Source定义了一种获取随机信息的方法:

Int63() int64

这个Source.Int63()方法返回63个随机位;为了快速(est),我们应该使用所有。当然,生成单个bool值只需要其中的一个位,但我们应该存储剩余的值,并在我们询问后续随机bool时使用它们。

这是如何做到的:

type boolgen struct {
    src       rand.Source
    cache     int64
    remaining int
}

func (b *boolgen) Bool() bool {
    if b.remaining == 0 {
        b.cache, b.remaining = b.src.Int63(), 63
    }

    result := b.cache&0x01 == 1
    b.cache >>= 1
    b.remaining--

    return result
}

创建这样的boolgen是这样的:

func New() *boolgen {
    return &boolgen{src: rand.NewSource(time.Now().UnixNano())}
}

使用示例:

r := New()
for i := 0; i < 100; i++ {
    if i%10 == 0 {
        fmt.Println()
    }
    fmt.Print(r.Bool(), " ")
}

示例输出(在Go Playground上尝试):

false false true true false false false false false false 
false false false true false false true false true true 
false false true false true false false true true true 
false false false false false false false true true false 
true true true true false false false false true false 
true true true false true true true true true true 
true true false true true false false true false true 
true true false false false true true true true false 
true false false true true true true false false true 
true false false false false false false false true false 

有些说明:

rand.NewSource()返回的Source对于多个goroutine并发使用是不安全的,因此我们的boolgen对于并发使用也不安全。一方面,这是,因为它会比使用rand包的默认来源更快(因为没有同步发生),这种方式是安全的(这是由未被移植的方式,所以只能通过rand包的功能间接地到达。

如果你需要在多个goroutine中使用它,最快(如问题的精神)将为所有goroutine创建自己的boolgen,因此不需要同步。

如果必须使boolgen本身对同时使用安全,则只需使用sync.Mutex保护其Bool()方法。

答案 2 :(得分:2)

我使用stdlib的math/rand包和go中的另一个伪随机数生成器github.com/MichaelTJones/pcg进行了不同方法的速度比较

这是我用来计时不同变体的代码:

package main

import (
    "fmt"
    "math/rand"
    "testing"

    "github.com/MichaelTJones/pcg"
)

func BenchmarkBool(b *testing.B) {

    pcg32 := pcg.NewPCG32()

    ff := []func() bool{
        func() bool { return rand.Intn(2) == 0 },          // 1
        func() bool { return rand.Int31n(2) == 0 },        // 2
        func() bool { return rand.Int63n(2) == 0 },        // 3
        func() bool { return rand.Float32() < .5 },        // 4
        func() bool { return rand.Float64() < .5 },        // 5
        func() bool { return rand.Int31()&(1<<30) == 0 },  // 6
        func() bool { return rand.Uint32()&(1<<31) == 0 }, // 7
        func() bool { return rand.Int63()&(1<<62) == 0 },  // 8
        func() bool { return rand.Uint64()&(1<<63) == 0 }, // 9
        func() bool { return pcg32.Random()&0x01 == 0 },   // 10
    }
    for i, f := range ff {
        b.Run(fmt.Sprintf("method%v", i+1), func(b *testing.B) {
            for n := 0; n < b.N; n++ {
                _ = f()
            }
        })
    }
}

在我的机器上,该程序的输出为

BenchmarkBool/method1-4             50000000            36.8 ns/op
BenchmarkBool/method2-4             50000000            34.7 ns/op
BenchmarkBool/method3-4             50000000            31.5 ns/op
BenchmarkBool/method4-4             50000000            33.3 ns/op
BenchmarkBool/method5-4             50000000            30.1 ns/op
BenchmarkBool/method6-4             50000000            29.4 ns/op
BenchmarkBool/method7-4             50000000            31.0 ns/op
BenchmarkBool/method8-4             50000000            28.7 ns/op
BenchmarkBool/method9-4             50000000            29.5 ns/op
BenchmarkBool/method10-4            300000000            4.86 ns/op

方法10最快,方法1最快。

答案 3 :(得分:0)

嗨,我使用这种方法,效果很好

random_bool.go

import (
      "math/rand"
      "time"
)

const (
    Agree = 1
    Disagree = 0
)

func AreYouAgree() bool {
    rand.Seed(time.Now().UnixNano())
    ran := rand.Intn(Agree + 1)
    if ran == Agree {
        return true
    }
    return false
}

感谢您阅读答案。 ;)