7

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

7
  • 1
    What is your use case? To me, it seems like you want a string made of 8 digits more than a number per se? This answer may help: stackoverflow.com/questions/22892120/… Commented Mar 15, 2016 at 2:38
  • @Ezra, the question is actually inspired by that one, which despite several iteration of performance improvement, still can't get rid of that loop. Yes, I do want string made of 8 digits more than a number per se. Even hex digits are fine with me. The point is, my above solution can finish in one shot, which I believe will be much much faster than the fastest solution there, which is far from simple. Commented Mar 15, 2016 at 2:47
  • 1
    There is nothing wrong with padding with zeros: A random number may start with one or more zeros if padded and is still totally random. Commented Mar 15, 2016 at 6:18
  • 1
    @Volker, There is nothing wrong with my personal taste not wanting the padding. You may like 00000023, or even 00000004 as the answers but I personally don't. I've already state that clearly in OP so I don't see the point your arguing about that -- It all comes down to personal taste, so please don't force yours onto others. Commented Mar 16, 2016 at 3:13
  • Please excuse if I hurt you feelings. I just didn't know that random numbers are more a matter of taste than of math. Sorry. Commented Mar 16, 2016 at 6:20

5 Answers 5

19

This is a general purpose function for generating numbers within a range

func rangeIn(low, hi int) int {
    return low + rand.Intn(hi-low)
}

See it on the Playground

In your specific case, trying to generate 8 digit numbers, the range would be (10000000, 99999999)

Sign up to request clarification or add additional context in comments.

2 Comments

this gives same number all the time.
If you are running outside the Go playground you can set the seed the PRNG before calling rand.Intn like rand.Seed(time.Now().UnixNano()). This will yield different, though still consistent between runs, values as well since the playground uses a hard-coded datatime.
4

It depend on value range you want to use.

  1. If you allow value range [0-99999999] and padding zero ip number of char < 8, then use fmt like fmt.Sprintf("%08d",rand.Intn(100000000)).

  2. If you dont want padding, which value in range [10000000, 99999999], then give it a base like ranNumber := 10000000 + rand.Intn(90000000)`

Comments

3

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
}

Comments

1

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
}

Comments

1

Easier version of random numbers would be:

func randNumber(n int) int {

    minLimit := int(math.Pow10(n))
    maxLimit := int(math.Pow10(n - 1))
    randInt := int(rand.Float64() * float64(minLimit))
    if randInt < maxLimit {
        randInt += maxLimit
    }
    return randInt
   
}

func main() {
    fmt.Println(randNumber(6))
}

This is useable for verification codes or similar uses

Returns a random number, Not a Unique Number. Please use UUID package, If you need UNIQUE number.

Playground Link

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.