ryboe
ryboe

Reputation: 2842

Generating random numbers over a range in Go

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.

Upvotes: 75

Views: 90850

Answers (9)

ryboe
ryboe

Reputation: 2842

For Go 1.22+:

Use the math/rand/v2 package.

import "math/rand/v2"

func randRange(min, max int) int {
    return rand.IntN(max-min) + min
}

For Go 1.21 and earlier:

import "math/rand"

func randRange(min, max int) int {
    return rand.Intn(max-min) + min
}

Please note that this returns numbers in the range [min, max), meaning that max is never returned. For example, randRange(1, 3) would return 1 and 2 only. It would never return 3. If you want numbers in the range [min, max], just add 1 as shown below:

return rand.IntN(max+1-min) + min

Upvotes: 121

Dan
Dan

Reputation: 2546

The question asks how to generate random numbers between min and max where max is not inclusive meaning max will never be reached.

For example, if min is 1 and max is 4 then it would only give you values from 1-3.

If you came here looking how to generate all numbers in min and max range then you need to adjust for that by adding +1.

rand.Intn(max + 1 - min) + min

Example of it working by showing which numbers were hit and how many times:

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    dat := make(map[int]int)
    for i := 0; i < 100000; i++ {
        x := getRandomInt(1, 4)
        dat[x] += 1
    }

    fmt.Println(dat)
}

func getRandomInt(min, max int) int {
    return rand.Intn(max + 1 - min) + min
}

Output:

map[1:24810 2:25194 3:25024 4:24972]

You can also randomly generate negative numbers. If we made min -5 and max 5 we get:

Output:

map[-5:9302 -4:9121 -3:9136 -2:8951 -1:9116 0:8928 1:9156 2:8970 3:9188 4:9045 5:9087]

Upvotes: 0

igops
igops

Reputation: 761

I agree with @Wolf's answer, however I'd add more OOP-alike style like that:

package main

import (
    "math/rand"
    "sync"
    "time"
)

type Random struct {
    source rand.Source
    mu     sync.Mutex
}

func (rnd *Random) Next(from int, to int) int {
    rnd.mu.Lock()
    if rnd.source == nil {
        rnd.source = rand.NewSource(time.Now().UnixNano())
    }
    rnd.mu.Unlock()
    return from + rand.New(rnd.source).Intn(to-from+1)
}

func main() {
    rnd := Random{}
    println(rnd.Next(1, 100))
}

Upvotes: 0

Righthanded Trex
Righthanded Trex

Reputation: 1

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

Upvotes: 0

MD Golam Rakib
MD Golam Rakib

Reputation: 144

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

Upvotes: 2

Wolf
Wolf

Reputation: 10238

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

Upvotes: 11

user11262312
user11262312

Reputation:

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.

Upvotes: 2

Asalle
Asalle

Reputation: 1337

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

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

source

Upvotes: 21

Alok Kumar Singh
Alok Kumar Singh

Reputation: 2569

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]

Upvotes: 2

Related Questions