英文:
generate a random bool in go
问题
在Go语言中生成随机布尔值的最快方法是使用rand.Intn(2) != 0。你的代码已经很不错了,但是如果你想进一步改进,可以考虑以下几点:
- 将随机数生成器的初始化放在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)
}
}
- 如果你需要生成大量的随机布尔值,可以考虑使用一个缓冲区来存储生成的随机数,以减少随机数生成器的调用次数。这样可以提高性能。
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 (
"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)
}
}
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 (
"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
}
I am not too familiar with go though, so please forgive my formating.
答案2
得分: 14
如何生成随机的bool
值的示例可以在这里找到(不一定是最快的解决方案,因为那不是一个要求):
这类算法中最慢的部分总是获取随机数据(随机信息)。例如,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):
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 bool
s 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&0x01 == 1
b.cache >>= 1
b.remaining--
return result
}
Creating such a boolgen
is like this:
func New() *boolgen {
return &boolgen{src: rand.NewSource(time.Now().UnixNano())}
}
Example usage:
r := New()
for i := 0; i < 100; i++ {
if i%10 == 0 {
fmt.Println()
}
fmt.Print(r.Bool(), " ")
}
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 (
"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()
}
})
}
}
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 (
"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
}
thanks for reading answer.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论