62

All the integer functions in math/rand generate non-negative numbers.

rand.Int() int              // [0, MaxInt]
rand.Int31() int32          // [0, MaxInt32]
rand.Int31n(n int32) int32  // [0, n)
rand.Int63() int64          // [0, MaxInt64]
rand.Int63n(n int64) int64  // [0, n)
rand.Intn(n int) int        // [0, n)

I would like to generate random numbers in the range [-m, n). In other words, I would like to generate a mix of positive and negative numbers.

ryboe
  • 2,435
  • 1
  • 20
  • 21
  • Your specification of range may be obvious to you and may be mathematically unambiguous, but most people are heavily attracted by symmetry, so many will think of the interval `[min,max]`. Well, maybe a matter of taste... – Wolf Dec 22 '16 at 12:33
  • 1
    In other words: Your *`mix of positive and negative numbers`* will be unbalanced. – Wolf Dec 22 '16 at 12:37

7 Answers7

96

I found this example at Go Cookbook, which is equivalent to rand.Range(min, max int) (if that function existed):

rand.Intn(max - min) + min

Don't forget to seed the PRNG before calling any rand function.

rand.Seed(time.Now().UnixNano())
ryboe
  • 2,435
  • 1
  • 20
  • 21
21

This will generate random numbers within given range [a, b]

rand.Seed(time.Now().UnixNano())
n := a + rand.Intn(b-a+1)

source

Asalle
  • 1,239
  • 19
  • 41
10

As to prevent repeating min and max over and over again, I suggest to switch range and random in thinking about it. This is what I found to work as expected:

package main

import (
    "fmt"
    "math/rand"
)

// range specification, note that min <= max
type IntRange struct {
    min, max int
}

// get next random value within the interval including min and max
func (ir *IntRange) NextRandom(r* rand.Rand) int {
    return r.Intn(ir.max - ir.min +1) + ir.min
}

func main() {
    r := rand.New(rand.NewSource(55))
    ir := IntRange{-1,1}
    for i := 0; i<10; i++ {
        fmt.Println(ir.NextRandom(r))
    }
}

See on Go Playground

Specifying the range

The solution you found in the Cookbook misses to exactly specify how min and max work, but of course it meets your specification ([-min, max)). I decided to specify the range as a closed interval ([-min, max], that means its borders are included in the valid range). Compared to my understanding of the Cookbook description:

gives you that random number within any two positive numbers that you specify (in this case, 1 and 6).

(which can be found below the code snippet in the Golang Cookbook)

the Cookbook implementation is off by one (which of course brings it in good company with lots of programs that are helpful at first glance).

Wolf
  • 9,679
  • 7
  • 62
  • 108
  • 2
    Good catch, @Wolf--I noticed the same issue with the Cookbook example. (This should have more votes, but the upvoters appear to have left SO a long time ago.) – SexxLuthor May 11 '17 at 06:14
  • ...well, you are still here ;) I think that my variation should be understood as a side note because the OP explicitly referred to `the range [-m, n)` which is the understanding of ranges that is most common to programmers, mostly not to users... BTW: isolating the interval *may* be interesting, sometimes helpful, but definitely challenging for good naming: Today, I'm a little bit confused about `IntRange`s that produce `NextRandom` values. – Wolf May 11 '17 at 14:29
  • it returns always the same results https://play.golang.org/p/pXZvtcmxjOq – rok Jul 29 '21 at 05:15
  • 1
    @rok The implementation of the go playground fakes the time, see [Inside the Go Playground - The Go Blog](https://blog.golang.org/playground) for the details, so I decided to go that way instead of [*failing on fake randomization*](https://stackoverflow.com/q/48360260/2932052) – Wolf Aug 09 '21 at 13:06
2

A small utility I wrote for generating random slices(very much like python range)

Code - https://github.com/alok87/goutils/blob/master/pkg/random/random.go

import "github.com/alok87/goutils/pkg/random"
random.RangeInt(2, 100, 5)

[3, 10, 30, 56, 67]
Alok Kumar Singh
  • 2,331
  • 3
  • 18
  • 37
2

Solution that worked for me is: j = rand.Intn(600) - 100 where m is 100 and n is 500, it will generate numbers from -100 to 499.

1

This worked for me (Generate random number between 1 and 10)...

import "math/rand"

rand.Seed(time.Now().UnixNano())
randId := rand.Intn(10-1) + 1
0

I solved this problem using for cycle. For example, you need to generate a number between 50 and 100:

val := rand.Intn(100) + 1    // determined the upper bound of the cycle
for val < 50 {
val = rand.Intn(100) + 1}   //   repeat the generation if the number is less than 50