generate a random bool in go

huangapple go评论143阅读模式
英文:

generate a random bool in go

问题

在Go语言中生成随机布尔值的最快方法是使用rand.Intn(2) != 0。你的代码已经很不错了,但是如果你想进一步改进,可以考虑以下几点:

  1. 将随机数生成器的初始化放在main函数之外,以避免重复初始化。例如,可以将初始化代码放在init函数中。
package main

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

// random generator
var r *rand.Rand

func init() {
	src := rand.NewSource(time.Now().UnixNano())
	r = rand.New(src)
}

func main() {
	for i := 0; i < 100; i++ {
		// generate a random boolean and print it
		fmt.Printf("bool: %v\n", r.Intn(2) != 0)
	}
}
  1. 如果你需要生成大量的随机布尔值,可以考虑使用一个缓冲区来存储生成的随机数,以减少随机数生成器的调用次数。这样可以提高性能。
package main

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

// random generator
var r *rand.Rand
var boolBuffer []bool

func init() {
	src := rand.NewSource(time.Now().UnixNano())
	r = rand.New(src)
}

func generateBoolBuffer(size int) {
	boolBuffer = make([]bool, size)
	for i := 0; i < size; i++ {
		boolBuffer[i] = r.Intn(2) != 0
	}
}

func main() {
	generateBoolBuffer(100)

	for i := 0; i < 100; i++ {
		// print the pre-generated random boolean
		fmt.Printf("bool: %v\n", boolBuffer[i])
	}
}

这样,你可以一次生成一批随机布尔值,并在需要时使用它们,而不必每次都调用随机数生成器。

希望这些改进能对你有所帮助!

英文:

What's the fastest way to generate a random bool in go ?

currently I'm doing like this :

package main

import (
	&quot;fmt&quot;
	&quot;math/rand&quot;
	&quot;time&quot;
)

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

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

How can I improve this ?

答案1

得分: 15

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

package randbool

import (
	"math/rand"
	"time"
)

/*
RandBool
    根据当前时间返回一个随机的布尔值
*/
func RandBool() bool {
	rand.Seed(time.Now().UnixNano())
	return rand.Intn(2) == 1
}

不过,我对Go语言不太熟悉,所以请原谅我的格式。

英文:

I am just a rookie, but this makes more sense to me than other solutions provided:

package randbool

import (
	&quot;math/rand&quot;
	&quot;time&quot;
)

/*
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
}

I am not too familiar with go though, so please forgive my formating.

答案2

得分: 14

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

https://stackoverflow.com/questions/44719156/how-can-i-let-a-function-randomly-return-either-a-true-or-a-false-in-go/44719269#44719269

这类算法中最慢的部分总是获取随机数据(随机信息)。例如,rand.Int31()调用返回31个随机位,但如果我们只用它来“生成”一个随机的bool值(即1位信息),我们就浪费了30位(可以是30个额外的随机bool值!)。

使用rand.Source是一个不错的选择,因为我们不需要rand.Rand在随机数据上执行的所有“代码功夫”。我们只需要一个随机信息的来源。

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

Int63() int64

这个Source.Int63()方法返回63个随机位;为了速度最快,我们应该全部使用。当然,生成一个单独的bool值只需要其中的1位,但我们应该存储剩余的位,并在后续需要随机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()方法即可。

英文:

Examples of how to generate a random bool value can be found here (not necessarily the fastest solutions, as that wasn't a requirement there):

https://stackoverflow.com/questions/44719156/how-can-i-let-a-function-randomly-return-either-a-true-or-a-false-in-go/44719269#44719269

The slowest part of such algorithms is always getting the random data (random information). For example a rand.Int31() call returns 31 random bits, but if we only use it to "generate" a random bool value (which is 1 bit of information), we waste 30 bits (which could be 30 additional random bool values!).

Using rand.Source is a good choice, as we don't need all the "code kung-fu" that rand.Rand does on the random data. We just need a source of random information.

rand.Source defines one method to obtain random information:

Int63() int64

This Source.Int63() method returns 63 random bits; to be fast(est), we should use all. Of course generating a single bool value requires only 1 of its bits, but we should store the remaining and use them when subsequent random bools are asked from us.

This is how it can be done:

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&amp;0x01 == 1
	b.cache &gt;&gt;= 1
	b.remaining--

	return result
}

Creating such a boolgen is like this:

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

Example usage:

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

Example output (try it on the 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 

Some notes:

The Source returned by rand.NewSource() is not safe for concurrent use by multiple goroutines, so our boolgen is also not safe for concurrent use. On one hand this is good, as it will be faster (as no synchronization takes place) than using the default source of the rand package which is safe in this manner (which is by the way unexported, so can only be "reached" indirectly through functions of the rand package).

If you need to use this from multiple goroutines, fastest (as in spirit of the question) would be for all goroutines to create their own boolgen, so no synchronization is needed.

If boolgen itself must be made safe for concurrent use, simply its Bool() method should be protected with a sync.Mutex.

答案3

得分: 3

我使用math/rand标准库和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最慢。

英文:

I did a speed comparison of different methods using math/rand package from stdlib and github.com/MichaelTJones/pcg, another pseudorandom number generator in go

Here is the code I used for timing the different variants:

package main
import (
&quot;fmt&quot;
&quot;math/rand&quot;
&quot;testing&quot;
&quot;github.com/MichaelTJones/pcg&quot;
)
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() &lt; .5 },        // 4
func() bool { return rand.Float64() &lt; .5 },        // 5
func() bool { return rand.Int31()&amp;(1&lt;&lt;30) == 0 },  // 6
func() bool { return rand.Uint32()&amp;(1&lt;&lt;31) == 0 }, // 7
func() bool { return rand.Int63()&amp;(1&lt;&lt;62) == 0 },  // 8
func() bool { return rand.Uint64()&amp;(1&lt;&lt;63) == 0 }, // 9
func() bool { return pcg32.Random()&amp;0x01 == 0 },   // 10
}
for i, f := range ff {
b.Run(fmt.Sprintf(&quot;method%v&quot;, i+1), func(b *testing.B) {
for n := 0; n &lt; b.N; n++ {
_ = f()
}
})
}
}

On my machine, the output of this program is

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

i.e. method number 10 is fastest, and number 1 is slowest.

答案4

得分: -1

你好,我使用这种方法,它运行良好。

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
}

谢谢阅读答案。;)

英文:

hi i use this approach and it's working well

random_bool.go

import (
&quot;math/rand&quot;
&quot;time&quot;
)
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
}

thanks for reading answer. generate a random bool in go

huangapple
  • 本文由 发表于 2017年7月11日 17:30:52
  • 转载请务必保留本文链接:https://go.coder-hub.com/45030618.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定