7

I want to have a function that I can call to get a random true or false on each call:

  randBoolean() // true
  randBoolean() // false
  randBoolean() // false
  randBoolean() // true

How can I return a random boolean?

Mister Verleg
  • 4,053
  • 5
  • 43
  • 68
  • 1
    You should seed your RNG using `rand.Seed` before generating any random number so that you get non-deterministic results. A quite good seed is the current time (`time.Now().UnixNano()`). – Makkes Jun 23 '17 at 10:36
  • 1
    See https://golang.org/pkg/math/rand/#Seed for an explanation of how `Seed` works and what happens when you don't call it. – Makkes Jun 23 '17 at 10:45

4 Answers4

19

You need some kind of random information, and based on its value, you can return true in half of its possible cases, and false in the other half of the cases.

A very simple example using rand.Float32() of the math/rand package:

func rand1() bool {
    return rand.Float32() < 0.5
}

Don't forget to properly seed the math/rand package for it to be different on each app run using rand.Seed():

func main() {
    rand.Seed(time.Now().UnixNano())
    fmt.Println(rand1())
}

This is mentioned in the package doc of math/rand:

Use the Seed function to initialize the default Source if different behavior is required for each run.

If you don't seed, the same pseudo-random information is returned on each application run.

Some variations:

func rand2() bool {
    return rand.Int31()&0x01 == 0
}

func rand3() bool {
    return rand.Intn(2) == 0
}

And an interesting solution without using the math/rand package. It uses the select statement:

func rand9() bool {
    c := make(chan struct{})
    close(c)
    select {
    case <-c:
        return true
    case <-c:
        return false
    }
}

Explanation:

The select statement chooses one random case from the ones that can proceed without blocking. Since receiving from a closed channel can proceed immediately, one of the 2 cases will be chosen randomly, returning either true or false. Note that however this is far from being perfectly random, as that is not a requirement of the select statement.

The channel can also be moved to a global variable, so no need to create one and close one in each call:

var c = make(chan struct{})

func init() {
    close(c)
}

func rand9() bool {
    select {
    case <-c:
        return true
    case <-c:
        return false
    }
}
icza
  • 389,944
  • 63
  • 907
  • 827
  • 2
    Small clarification: You say _Don't forget to properly seed the math/rand package for it to be random_. The functions **are** random, just that they are always seeded with the same value (1) when `rand.Seed()` is not called. This can actually be a desired behaviour (e.g. for testing things). – Makkes Jun 23 '17 at 10:48
2

This function returns true if the random integer is even else it returns false:

func randBool() bool{
    return rand.Int() % 2 == 0
}
adjan
  • 13,371
  • 2
  • 31
  • 48
1

The easiest way will be to create a random number and then take its modulus of 2. Then if it is 0 the return true and if it is 1 then return false.

Aravind A R
  • 2,674
  • 1
  • 15
  • 25
0

Here's another one liner, requires no random number generation/seeding etc., fairly simple :

package main

import (
    "fmt"
    "time"
)

func main() {
    fmt.Println("Got random bool:", getRandBool())
}

func getRandBool() bool {
    now := time.Now()
    nowNano := now.Nanosecond()
    fmt.Println(nowNano)
    return now.UnixNano()%2 == 0
}

Edited after @icza's comments : time.Now() is supposed to return time with nanosecond accuracy, but on Windows 10 Pro 64-bit (and I tried with go 1.8 & it may be true with other Windows OS too) it always returns time with lesser precision (probably micro second), rounding off the result so that it'll end with xxxxx..00 and hence this function will return true always. I have modified the function so one can see the result also. Works fine on Linux & probably should on other Unix OS'es too. So either use this function only after testing or better don't use if you need to deploy on a Windows system. It's unfortunate and hard to believe this, but it's a reality, bad Windows implementation. Thanks @icza for pointing out.

Ravi R
  • 1,692
  • 11
  • 16
  • 2
    It should be noted that the "randomness" of your `getRandBool()` using `Time.UnixNano()` greatly depends on the granularity on the system clock. On some Windows this may **always** return `true`, which is a "constant" and not even remotely random... – icza Jun 23 '17 at 13:26
  • Ok. Which version of Windows are you mentioning about? Can you please share relevant URL's on this issue? – Ravi R Jun 23 '17 at 16:00
  • 3
    Check out this question: [How precise is Go's time, really?](https://stackoverflow.com/questions/14610459/how-precise-is-gos-time-really) – icza Jun 23 '17 at 16:29
  • 1
    I just investigated this a bit more. If you look at go source code time.go (https://golang.org/src/time/time.go), you'll find that the Now() function calls a function now() which is implemented in go runtime. If you look at the go runtime code https://golang.org/src/runtime/time.go, you'll find a comment which mentions that time.now is implemented in assembly, and I don't know if we can get better accuracy than that. – Ravi R Jun 24 '17 at 03:02