Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

generate a random bool in go

Tags:

random

boolean

go

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 ?

like image 634
felix Avatar asked Jul 11 '17 09:07

felix


People also ask

How to generate random numbers in go?

Golang has built-in support for random number generation in the standard library. Specifically there is the math/rand package which implements pseudo-random number generators. Intn returns, as an int, a non-negative pseudo-random number in [0,n) from the default Source.

How do you do a random bool?

In order to generate Random boolean in Java, we use the nextBoolean() method of the java. util. Random class. This returns the next random boolean value from the random generator sequence.

How to get the random value in golang?

Go rand. The rand. Intn function returns, as an int, a non-negative pseudo-random number in [0,n) from the default source. The example prints five random integers. To get different pseudo random values, we seed the random generator with time.

What is math rand in Golang?

Golang provides a package math/rand for generating pseudorandom numbers. This package basically uses a single source that causes the production of a deterministic sequence of values each time a program is executed.


Video Answer


3 Answers

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):

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

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&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.

like image 95
icza Avatar answered Oct 26 '22 09:10

icza


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.

like image 13
Robert J Avatar answered Oct 26 '22 10:10

Robert J


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.

like image 3
jochen Avatar answered Oct 26 '22 11:10

jochen