How to generate a fixed length random number in Go?

Viewed 11959

What is the fastest and simplest way to generate fixed length random numbers in Go?

Say to generate 8-digits long numbers, the problem with rand.Intn(100000000) is that the result might be far less than 8-digits, and padding it with leading zeros doesn't look like a good answer to me.

I.e., I care about the the quality of the randomness more in the sense of its length. So I'm thinking, for this specific problem, would the following be the fastest and simplest way to do it?

99999999 - rand.Int63n(90000000)

I.e., I guess Int63n might be better for my case than Intn. Is it ture, or it is only a wishful thinking? Regarding randomness of the full 8-digits, would the two be the same, or there is really one better than the other?

Finally, any better way than above?

UPDATE:

Please do not provide low + rand(hi-low) as the answer, as everyone knows that. It is equivalent of what I'm doing now, and it doesn't answer my real question, "Regarding randomness of the full 8-digits, would the two be the same, or there is really one better than the other? "

If nobody can answer that, I'll plot a 2-D scatter plot between the two and find out myself...

Thanks

4 Answers

See it on Playground

crypto/rand package is used to generate number.

func generateRandomNumber(numberOfDigits int) (int, error) {
    maxLimit := int64(int(math.Pow10(numberOfDigits)) - 1)
    lowLimit := int(math.Pow10(numberOfDigits - 1))

    randomNumber, err := rand.Int(rand.Reader, big.NewInt(maxLimit))
    if err != nil {
        return 0, err
    }
    randomNumberInt := int(randomNumber.Int64())

    // Handling integers between 0, 10^(n-1) .. for n=4, handling cases between (0, 999)
    if randomNumberInt <= lowLimit {
        randomNumberInt += lowLimit
    }

    // Never likely to occur, kust for safe side.
    if randomNumberInt > int(maxLimit) {
        randomNumberInt = int(maxLimit)
    }
    return randomNumberInt, nil
}

I recently needed to do something like this, but with a certain byte length (rather than number of digits) and with numbers larger than max int64 (so using math/big.Int). Here was my general solution:

See on the Playground (with added code comments)

func generateRandomBigInt(numBytes int) (*big.Int, error) {
    value := make([]byte, numBytes)
    _, err := rand.Reader.Read(value)
    if err != nil {
        return nil, err
    }

    for true {
        if value[0] != 0 {
            break
        }
        firstByte := value[:1]
        _, err := rand.Reader.Read(firstByte)
        if err != nil {
            return nil, err
        }
    }

    return (&big.Int{}).SetBytes(value), nil
}
Related