Generating Random Integers and Unique Random Sequences in Go

Random Integer Genreation

// GenerateRandomInt returns a random integer within the specified range [min, max)
func GenerateRandomInt(min int, max int) (int, error) {
    if min >= max {
        return 0, fmt.Errorf("invalid range: min %d >= max %d", min, max)
    }
    
    seed := time.Now().UnixNano()
    randomizer := rand.New(rand.NewSource(seed))
    
    return randomizer.Intn(max-min) + min, nil
}

Generating Unique Random Sequences

// GenerateUniqueRandomSequence creates a slice of unique random integers in range [min, max)
func GenerateUniqueRandomSequence(min, max, size int) ([]int, error) {
    if min >= max {
        return nil, fmt.Errorf("invalid range [%d, %d)", min, max)
    }
    if size > max-min {
        return nil, fmt.Errorf("requested size %d exceeds available numbers %d", size, max-min)
    }
    
    // Create sequential slice of all possible numbers
    availableNumbers := make([]int, max-min)
    for i := range availableNumbers {
        availableNumbers[i] = min + i
    }
    
    // Shuffle using cryptographic random seed
    cryptoSeed, _ := rand.Int(rand.Reader, big.NewInt(1<<63-1))
    shuffler := rand.New(rand.NewSource(cryptoSeed.Int64()))
    shuffler.Shuffle(len(availableNumbers), func(i, j int) {
        availableNumbers[i], availableNumbers[j] = availableNumbers[j], availableNumbers[i]
    })
    
    return availableNumbers[:size], nil
}

Optimized Algorithm for Large Ranges

func GenerateUniqueRandomNumbers(min, max, count int) ([]int, error) {
    if min >= max {
        return nil, fmt.Errorf("invalid range [%d, %d)", min, max)
    }
    if count > max-min {
        return nil, fmt.Errorf("count %d exceeds range size %d", count, max-min)
    }
    
    totalNumbers := max - min
    
    // For small ranges or when selecting most numbers, use shuffle approach
    if totalNumbers <= 1000 || count > totalNumbers/2 {
        sequence := make([]int, totalNumbers)
        for i := 0; i < totalNumbers; i++ {
            sequence[i] = min + i
        }
        
        cryptoSeed, _ := rand.Int(rand.Reader, big.NewInt(1<<63-1))
        rng := rand.New(rand.NewSource(cryptoSeed.Int64()))
        rng.Shuffle(len(sequence), func(i, j int) {
            sequence[i], sequence[j] = sequence[j], sequence[i]
        })
        
        return sequence[:count], nil
    }
    
    // For large ranges, use reservoir sampling
    result := make([]int, count)
    for i := 0; i < count; i++ {
        result[i] = min + i
    }
    
    cryptoSeed, _ := rand.Int(rand.Reader, big.NewInt(1<<63-1))
    rng := rand.New(rand.NewSource(cryptoSeed.Int64()))
    
    for i := count; i < totalNumbers; i++ {
        randomIndex := rng.Intn(i + 1)
        if randomIndex < count {
            result[randomIndex] = min + i
        }
    }
    
    return result, nil
}

Both functions utilize time-based seeding suitable for general use cases. For enhanced security requirements, cryptographic random number generation provides stronger ranodmness guarantees.

Tags: Go Golang Random algorithms programming

Posted on Mon, 26 Oct 2026 16:46:17 +0000 by jpschwartz