如何在 Go 中让一个函数随机返回 true 或 false?

8

我想要一个函数,每次调用可以随机返回truefalse值:

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

如何返回一个随机的布尔值?


1
在生成任何随机数之前,您应该使用rand.Seed种子化您的 RNG,以便获得非确定性结果。一个相当不错的种子是当前时间(time.Now().UnixNano())。 - Makkes
1
请参阅 https://golang.org/pkg/math/rand/#Seed 了解 Seed 如何工作以及在不调用它时会发生什么的说明。 - Makkes
4个回答

20
你需要一些随机信息,基于它的值,在其可能情况下返回一半的true和另一半的false。使用rand.Float32()来演示非常简单,它是math/rand包中的函数。
func rand1() bool {
    return rand.Float32() < 0.5
}

不要忘记适当地使用rand.Seed()来种子化math/rand包,以使其在每次应用程序运行时都不同:
func main() {
    rand.Seed(time.Now().UnixNano())
    fmt.Println(rand1())
}

这在math/rand的包文档中提到:
使用Seed函数初始化默认Source,如果需要每次运行不同的行为,则需要不同的Seed值。
如果不进行Seed操作,则每次应用程序运行时返回相同的伪随机信息。
一些变化:
func rand2() bool {
    return rand.Int31()&0x01 == 0
}

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

这是一种不使用 math/rand 包的有趣解决方案。它使用了 select 语句:

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

解释:

select语句从可以不阻塞的案例中选择一个随机案例。由于从关闭的通道接收可以立即进行,因此将随机选择2个案例之一,返回truefalse。请注意,这远非完全随机,因为这并不是select语句的要求。

通道也可以移动到全局变量中,因此每次调用时无需创建通道和关闭通道:

var c = make(chan struct{})

func init() {
    close(c)
}

func rand9() bool {
    select {
    case <-c:
        return true
    case <-c:
        return false
    }
}

2
小澄清:您说“不要忘记适当地为math/rand包种子化,以使其随机”。这些函数确实是随机的,只是当未调用rand.Seed()时,它们总是使用相同的值(1)进行种子化。这实际上可能是一种期望的行为(例如用于测试)。 - Makkes

2

如果随机整数是偶数,则此函数返回true,否则返回false:

func randBool() bool{
    return rand.Int() % 2 == 0
}

1
最简单的方法是创建一个随机数,然后取它对2的模。 如果结果是0,则返回true,如果结果是1,则返回false。

0

这是另一个单行代码,不需要任何随机数生成/种子等,非常简单:

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
}

在@icza的评论后进行了编辑:time.Now()应该返回纳秒精度的时间,但在Windows 10 Pro 64位上(我尝试过go 1.8,并且可能适用于其他Windows操作系统),它总是以较低的精度(可能是微秒)返回时间,四舍五入结果,以便它以xxxxx..00结尾,因此此函数将始终返回true。我已修改了函数,以便可以看到结果。在Linux上运行良好,可能在其他Unix操作系统上也是如此。因此,如果需要部署在Windows系统上,请在测试后仅使用此功能或最好不要使用。这很不幸,很难相信,但这是现实,是糟糕的Windows实现。感谢@icza指出。


2
应注意,使用Time.UnixNano()生成随机getRandBool()的“随机性”非常依赖于系统时钟的粒度。在某些Windows上,这可能始终返回true,这是一个“常数”,并不是完全随机的... - icza
好的。您提到的是哪个版本的Windows?您能否分享相关的URL链接来解决这个问题? - Ravi R
3
看看这个问题:Go语言的时间精度到底有多高? - icza
1
我刚刚进一步调查了一下。如果您查看Go源代码time.go(https://golang.org/src/time/time.go),您会发现Now()函数调用一个在Go运行时中实现的now()函数。如果您查看Go运行时代码https://golang.org/src/runtime/time.go,您会发现其中有一个注释提到time.now是用汇编语言实现的,我不知道是否能够获得比这更好的精度。 - Ravi R

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接