13

The official tour of Go gives the following code in the sandbox:

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    fmt.Println("My favorite number is", rand.Intn(10))
}

And this instruction:

Note: the environment in which these programs are executed is deterministic, so each time you run the example program rand.Intn will return the same number. (To see a different number, seed the number generator; see rand.Seed.)

After reading the entry under the official documentation for rand.Seed and reading this answer, I still can't correctly seed the random number generator.

Can someone please demonstrate how the rand.Seed function should be used to seed the random number generator?

Many thanks, Jon

jonsanders101
  • 525
  • 1
  • 6
  • 13

3 Answers3

12

By default rand.Intn uses the globalRand.Intn. Its created internally, refer here. So when you set via rand.Seed

rand.Seed(time.Now().UTC().UnixNano())

Then globalRand uses the new seed value.

When needed you can create your own rand generator with seed value. Refer to godoc example.


Play Link (without seed): https://play.golang.org/p/2yg7xjvHoJ

Output:

My favorite number is 1
My favorite number is 7
My favorite number is 7
My favorite number is 9
My favorite number is 1
My favorite number is 8
My favorite number is 5
My favorite number is 0
My favorite number is 6

Play Link (with seed): https://play.golang.org/p/EpW6R5rvM4

Output:

My favorite number is 0
My favorite number is 8
My favorite number is 7
My favorite number is 2
My favorite number is 3
My favorite number is 9
My favorite number is 4
My favorite number is 7
My favorite number is 8

EDIT:

As @AlexanderTrakhimenok mentioned, in playground program execution is deterministic. However, the playground doesn't stop you from supplying rand.Seed value.

Remember Seed value is int64.

When you rand.Intn, it uses default seed value 1 for globalRand.

var globalRand = New(&lockedSource{src: NewSource(1).(Source64)})

And in playground time.Now().UTC().UnixNano() gives you same value 1257894000000000000 since the start time is locked to a constant. But it is different from default seed value, that's why second playground link produces the different result.

So above two would produce the same result always.

How should we change the result in playground?

Yes, we can. Let's supply UnixNano() value 1500909006430687579 to rand.Seed, which is generated from my machine.

Play Link: https://play.golang.org/p/-nTydej8YF

Output:

My favorite number is 3
My favorite number is 5
My favorite number is 3
My favorite number is 8
My favorite number is 0
My favorite number is 5
My favorite number is 4
My favorite number is 7
My favorite number is 1
Abhishek K
  • 381
  • 4
  • 10
jeevatkm
  • 4,571
  • 1
  • 23
  • 24
  • 1
    Is it possible to seed without relying on time? Playground has a deterministic behavior for above code because the time in playground always starts at 2009-11-10 23:00:00 UTC. So, while this code would work on most platforms, it fails to produce a random seed for rand. – hbagdi Jul 23 '17 at 22:27
  • @hbagdi `rand.Seed` takes `int64`, so we can supply any compatible value other than time. Time is typically used for examples and sometimes as actually seed value too. – jeevatkm Jul 23 '17 at 23:03
  • How would you automate such a random in64 behavior for the random generator seed itself? – hbagdi Jul 23 '17 at 23:16
  • @hbagdi What do you mean by automate? I didn't get your question. Can you please explain? – jeevatkm Jul 23 '17 at 23:25
  • Is there another way truly random way to seed the random generator other than using time? – hbagdi Jul 23 '17 at 23:27
  • Yes, you can use package `crypto/rand` to generate random number (which internally uses `/dev/urandom` on *nix systems) and seed it to `rand.Seed`. – jeevatkm Jul 24 '17 at 00:25
  • 1
    @jeevatkm, The topic's starter asked about seeding random randomly in the Go Playground what is not possible as far as I know. See my answer. – Alexander Trakhimenok Jul 24 '17 at 08:55
  • @AlexanderTrakhimenok Thanks for your comment. I have added further explanation and one more example to the answer. – jeevatkm Jul 24 '17 at 15:28
  • It is actually possible :) I added an example – zeg Jan 05 '23 at 15:43
5

As you quoted yourself:

the environment in which these programs are executed is deterministic.

So the Go Playground by design does not allow to create truly pseudo-random outputs.

This is done intentionally for purpose of caching results to minimize CPU/memory usage for consequent runs. So the engine can evaluate your program just once and serve the same cached output every time when you or anyone else run it again.

For the same purpose the start time is locked to a constant.

You may want to read a blog post on how and why it's implemented this way: https://blog.golang.org/playground

Alexander Trakhimenok
  • 6,019
  • 2
  • 27
  • 52
0

For anyone who really needs a pseudo-random seed in go playground, just don't use the constant timestamp. You can access the execution memory usage which is slightly different on each execution in go playground even in the sandbox. So your seed can very well be non-deterministic and actually somewhat pseudo-random like this:

package main

import (
    "fmt"
    "math/rand"
    "strings"
    "time"
    "github.com/shirou/gopsutil/mem"
)

var extraSeed int64 = 1

func main() {
    memStat, err := mem.VirtualMemory()
    if err == nil {
        extraSeed = (int64)(memStat.Used)
    }
    fmt.Println("extra seed : ", extraSeed)
    
    rand.Seed(time.Now().UnixNano() + extraSeed) //<---- 
    // extraSeed will work randomly even in go playground,
    // since mem-Usage is eventually slightly different each time we execute it
    
    
    // do something random, for example shuffle
    orderedList := []string{"a","b","c","d","e"}
    
    rand.Shuffle(len(orderedList), func(i, j int) {
        orderedList[i], orderedList[j] = orderedList[j], orderedList[i]
    })
    fmt.Println("This should be random shuffeled: ", orderedList)
    
}

Maybe this is also a good idea if you fear that someone is tempering with your system clock to break your randomness... However that is just a more safe but still a pseudo-randomness.

If you have this kind of thoughts you might want to use cryptography safe random numbers instead :)

Hope that helps

zeg
  • 432
  • 2
  • 9