Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Cover image for Golang: Random Numbers
Meet Rajesh Gor
Meet Rajesh Gor

Posted on • Originally published atmeetgor.com

     

Golang: Random Numbers

Introduction

In the 27th post of the series, we will be looking into random number generation in golang. We will be exploring how to create a random number, generate random numbers within a range, shuffle slices/arrays, and generate random strings, float, and bytes.

There are two types of random number generation processes in software pseudo-random numbers and cryptographically secure pseudo-random number generation.

Themath/rand package in Golang provides a number of functions for generating pseudorandom numbers. These functions are suitable for a variety of applications, such as games, simulations, and to some extent in cryptography.

Thecrypto/rand package in Golang generates cryptographically secure pseudorandom numbers. This means that the numbers are generated in a way that is very difficult to predict or reproduce. However, they are not truly random, as they are generated by a computer algorithm.

Creating a Random Source

We need to first create a source/seed to generate a random number. If we do not add a new source each time we run the program or generate a random number, it will pick up the same source leading to the generation of the same pattern of the random numbers.

We use therand.NewSource method to generate a new source of the random number, by initializing it with the current time in nanoseconds. Further, we need to create aRand object for accessing the methods and properties attached to the struct type in the rand package for generating random numbers.

packagemainimport("fmt""math/rand""time")funcmain(){source:=rand.NewSource(time.Now().UnixNano())rand_source:=rand.New(source)fori:=0;i<5;i++{rand_num:=rand_source.Int()fmt.Println(rand_num)}}
Enter fullscreen modeExit fullscreen mode
$go run rand_source.go 26516530799348751205510445616427469234381701115946341591257087542243622556597511308401304127761
Enter fullscreen modeExit fullscreen mode

In the above example, we use theNewSource and theNew method to generate theSource and theRand object respectively. Further, for demonstration, we use theIntmethod to generate a 64-bit random integer 5 times with a for loop.

As we can see it generates a 5 random number, we will see why we need the random source initialized to the current time in the upcoming section.

Generating Random Numbers

Random number as the name suggest are used to get an unpredictable number, however, using software we can only mimic the actual randomness. The process is called pseudo-random number generation. There is a particular pattern in the numbers, however, it is sufficient for trivial tasks in games, and simulations to some extent. However, actual cryptographic random numbers should be used for security tasks, crypto arithmetic, and other sensitive tasks.

Golang provides a built-in package for both generating pseudo-random numbers called math/rand and cryptographic numbers with crypto/rand packages. This package contains a number of functions for generating random integers, floats, and strings.

Random Numbers

To simply generate a random number we can use therand.Int method from thematch/rand package to get a single random integer.

packagemainimport("fmt""math/rand")funcmain(){fmt.Println(rand.Int())num:=rand.Int()fmt.Printf("%d",num)}
Enter fullscreen modeExit fullscreen mode
$go run main.go5577006791947779410int 8674665223082153551$go run main.go5577006791947779410int 8674665223082153551
Enter fullscreen modeExit fullscreen mode

In the above code, we have generated a couple of random numbers with therand.Int method. The method returns a random 64-bit integer. If you run the program a few times, you can see the numbers are the same, so how exactly are they random?

They are not random yet, we need to create a new seed/source each time we run the program in order to generate a new pattern of digits each time to generate a pseudo-random number.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))fmt.Println(r.Int())num:=r.Int()fmt.Printf("%d",num)}
Enter fullscreen modeExit fullscreen mode
$go run main.go5577006791947779410int 86746652230821535517524437893560534176int 5023070266853767708$go run main.go5577006791947779410int 86746652230821535518935404877937414882 int 209789266380754935
Enter fullscreen modeExit fullscreen mode

No, we can see that after therand.New(rand.NewSource(time.Now().UnixNano())) function call, the number generated is random each time we run the program. This is because we initialize the source of the random number generator package to the current time in nanoseconds.

Random Numbers in a Range

The above numbers are too big, what if we want the random numbers to be in a specific range? This is quite a common thing to do, and hence there is a function likerand.Intn where we can specify the bound to which the function should generate the random numbers.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))fori:=0;i<10;i++{// generate an integer between 0 and 5dice_throw:=r.Intn(6)// Move the Offset of 0fmt.Println(dice_throw+1)}}
Enter fullscreen modeExit fullscreen mode
$go run main.go1256636142
Enter fullscreen modeExit fullscreen mode

In the above code, we have used ther.Intn(upper_range int) method to generate a random number between 0 and the provided range, so if we give a parameter to the methodr.Intn(6), it would generate the numbers between 0 and 5. so the range is not inclusive 0, 6). Thereby the numbers generated will be either 0, 1, 2, 3, 4, or 5. So to remove the offset of 0, we add 1.

Hence we get some pseudo-random numbers between 1 and 6. I have used a for loop that generates 10 such numbers.

Cryptographic Random Numbers

The above method was a pseudo-random number generator, however, for more robust random number generations, we can use thecrypto/rand package that is more secure and powerful for complex operations.

packagemainimport(crypto_rand"crypto/rand""fmt""math/big")funcHandle_error(errerror){iferr!=nil{panic(err)}}funcmain(){// Cryptographic random numbersvarmax*big.Int=big.NewInt(6)// big is a package for high-precision arithmeticfori:=0;i<10;i++{crypt_rand_num,err:=crypto_rand.Int(crypto_rand.Reader,max)Handle_error(err)// Move the Offset of 0 by adding 1crypt_num:=crypt_rand_num.Add(crypt_rand_num,big.NewInt(1))fmt.Println(crypt_num)}}
Enter fullscreen modeExit fullscreen mode
$go run main.go3551554236
Enter fullscreen modeExit fullscreen mode

In the above example, we have used themath/big package to store the random number generated by theInt method in thecrypto/rand package. We create a new integer from thebig package. TheNewInt function returns a pointer to the integer. So, we parse the integer 6 which will create a memory location storing 6 as abig.Int type. We use the max variable name as it denotes the maximum number to be generated in the next step.

Then we can use thecrypto/rand package to generate cryptographic random numbers. The package hasInt method to generate abig.Int type of number in a given range. However, it also takes in aReader object that is global in the package used as a shared instance of a cryptographically secure random number generator. This means it can be used as the platform's default random number generator in the program.

So, thecrypto_rand.Int method takes in two parameters, theReader object which will be the platform-specific random number generator/api, and the next parameter is the max range to generate the random number. So, this method returns abig.Int type. This is the cryptographic random number.

However, we have the range from 0 to 5 again, so we just add 1 to thebig.Int type by using theAdd method associated to thebig.Int type ascrypto_rand_num variable and then parse two parameters as x and y, i.e. the two numbers to add. So, we just pass thecrypto_rand_num and a new integer1. This adds the numbers and we store it in thecrypto_num variable. This is how we generate a cryptographic random number between 1 and 6.

Random Float

We can even generate random types like float. There are a quite a few variations likeFloat32,Float64,ExpFloat64, andNormFloat64.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))rand_float32:=r.Float32()fmt.Println(rand_float32)rand_float64:=r.Float64()fmt.Println(rand_float64)rand_exp_float:=r.ExpFloat64()fmt.Println(rand_exp_float)rand_norm_float:=r.NormFloat64()fmt.Println(rand_norm_float)fori:=0;i<5;i++{rand_float:=r.Float32()fmt.Println(rand_float)}
Enter fullscreen modeExit fullscreen mode
$go run main.go0.088910880.92182210786168241.8237338579299396-0.302387781603734640.654748560.659646870.399301980.80433380.17894344
Enter fullscreen modeExit fullscreen mode

We have used 4 types for generating a random float. We have two variations of the float depending on the size, 32 or 64-bit number. We get 32-bit and 64-bit random floats from ther.Float32 andr.Float64 respectively.

Ther.ExpFloat64 function returns an exponentially distributed float64 with a range from 0 to +math.MaxFloat64 with rate parameter and mean as 1. If you want to change the distribution's rate parameter, it can be done by dividing the number by the desired rate parameter.

Ther.NormFlaot64 function returns a normally distributed float64 with a range from -math.MaxFloat64 to +math.MaxFloat64 with mean as 0 and standard deviation as 1. This can also be changed by multiplying the generated number by the desired standard deviation and then adding the desired mean.

Generating Random Strings

We can generate a random string of a specific length. We can generate a random number between 0 and 25 and then add 97 for lowercase ASCII characters and add 65 for uppercase characters. So, we generate a random number between 97 and 122 which can be cast to string/rune to get the string equivalent of the numbers.

This get's us a single character which would be random and thereby we use for loop to generate a fixed length random string for upper case and lower case characters similarly.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))//Random stringrandomLowerCase:=make([]rune,6)randomUpperCase:=make([]rune,6)fori:=rangerandomLowerCase{randomLowerCase[i]=rune(r.Intn(26)+97)randomUpperCase[i]=rune(r.Intn(26)+65)}randomLowerCaseStr:=string(randomLowerCase)randomUpperCaseStr:=string(randomUpperCase)fmt.Println(randomLowerCase)fmt.Println(randomLowerCaseStr)fmt.Println(randomUpperCase)fmt.Println(randomUpperCaseStr)}
Enter fullscreen modeExit fullscreen mode
$go run main.go[100 113 122 97 107 101]dqzake[86 81 88 76 66 74]VQXLBJ$go run main.go[116 115 120 97 100 111]tsxado[80 74 66 83 77 66]PJBSMB
Enter fullscreen modeExit fullscreen mode

We first create an empty or 0 initialized rune slice with length 6, it can be any length as per your requirement. Then we create a for loop iterating over that slice and set each rune to ther.Intn method with range 26 and add 97 for lower case letters and add 65 for upper case letters. This generates an integer between 97 to 122 that is typecast to a rune to represent the slice. Similarly, it generates an integer between 65 and 90 which is typecast to rune.

Shuffling Arrays

We can use therand.Shuffle and therand.Perm to shuffle and create a random permutation of a particular list/slice of elements.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))fmt.Println(r.Perm(10))arr:=[]int{1,2,3,4,5,6}fmt.Println("Before shuffle:",arr)r.Shuffle(len(arr),func(i,jint){arr[i],arr[j]=arr[j],arr[i]})fmt.Println("After shuffle:",arr)}
Enter fullscreen modeExit fullscreen mode
$go run main.go[8 1 9 3 7 2 0 6 5 4]Before shuffle:[1 2 3 4 5 6]After shuffle:[4 6 5 3 2 1]
Enter fullscreen modeExit fullscreen mode

In the above example, we have used therand.Perm method to create a permutation of the n number passed as a parameter. So, it would generate a permutation of numbers from 0 to 9 if we pass 10 as the parameter to the method. It would return a slice of int.

We also have used therand.Shuffle method to shuffle an already existing slice of elements. This is not restricted to int, it can be any type of slice. The method takes in two parameters, the length of the slice/array and the swap function which is an anonymous function.

In the example, I have created an arr slice with 6 elements, it could be any number, for demonstration, I have initialized the slice with 1 to 6 numbers. Therand.Shuffle method has been parsed with the length of thearr aslen(arr) and an anonymous function that takes in two integers as the indices of the array and inside the function, we swap the elements of the array. This can be modified as per the requirement, but this is the base swap function for the shuffle method.

So, in the output, we print the shuffled array, which now looks like a random array of numbers.

We can use thePerm method to generate a random list of indices of an array, and then assign the index to the string, to generate a random shuffled string.

packagemainimport("fmt""math/rand""time")funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))letters:="abcdefghijklmnopqrstuvwxyz"shuffled:=r.Perm(len(letters))result:=make([]byte,len(letters))fori,randIndex:=rangeshuffled{result[i]=letters[randIndex]}rand_str:=string(result)fmt.Println(rand_str)// random string of length 10fmt.Println(rand_str[:10]}
Enter fullscreen modeExit fullscreen mode
$go run main.goyeinvkdbfqomacrzhtswgxulpjyeinvkdbfq$go run main.gotvakbgnjprwiofquxlzecdshymtvakbgnjpr
Enter fullscreen modeExit fullscreen mode

In the above example, we have first created the string with all the alphabets and then created a random permutation with the length of that array i.e. 26. This would create a random permutation of numbers from 0 to 25. This is now a list of numbers, which can be used to assign the index of the string, to make it feel like a shuffled string.

We create a for loop for the string iteration and assign the index with the random operation array index. This will basically jumble the order of the elements/characters in the string. We can then truncate or slice the string to any length as per the requirement.

Random Read Bytes

There is another way to generate a slice of bytes/string with theRead method. We have used theRead method in the cryptographic random number generation part. The Read method generates a random byte for the given length of a slice of bytes.

packagemainimport(crypto_rand"crypto/rand""fmt""math/big""math/rand""time")funcHandle_error(errerror){iferr!=nil{panic(err)}}funcmain(){r:=rand.New(rand.NewSoure(time.Now().UnixNano()))rand_byte:=make([]byte,5)fmt.Println(rand_byte)_,err=r.Read(rand_byte)Handle_error(err)fmt.Println(rand_byte)fmt.Printf("%c\n",rand_byte)crypt_rand_byte:=make([]byte,5)fmt.Println(crypt_rand_byte)_,err=crypto_rand.Read(crypt_rand_byte)Handle_error(err)fmt.Println(crypt_rand_byte)fmt.Printf("%c\n",crypto_rand_byte)}
Enter fullscreen modeExit fullscreen mode
$go run main.go[0 0 0 0 0][88 53 113 116 251][X 5 q t û][0 0 0 0 0][37 90 42 93 96][% Z*]`]
Enter fullscreen modeExit fullscreen mode

We have demonstrated usage of both the packages i.e. math/rand and crypto/rand for the generation of random bytes. In the example above, we initialize a slice of byterand_byte and use theRead method that will take in the slice of byte as the parameter and return two things, the number of bytes it read and the error object if there is any or nil. So, we do not care how many bytes it read right now, so we do the_ for the read bytes. It mutates/modifies the byte slice and the slice elements are then random byte values.

We can print the slice of byte as a string with%s, or each character in the bytes using the%c format specifier. So, the generated bytes are between 0 and 255, which include Unicode and ASCII characters.

Similarly, for the crypto/rand package, we create a slice of bytes with size 5 and use the crypto/rand package providedRead method directly to modify the slice of bytes to random bytes.

That's it from the 27th part of the series, all the source code for the examples are linked in the GitHub on the100 days of Golang repository.

Conclusion

From this part of the series, we were able to explore the random number generation in golang, packages like math/rand, mah/big, and crypto/rand were used for the examples and generation of random numbers, cryptographic secure random numbers, random strings and shuffling of arrays.

So, hopefully, the article might have found useful to you, if you have any queries, questions, feedback, or mistakes in the article, you can let me know in the discussion or on my social handles. Happy Coding :)series: "['100-days-of-golang']"

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Meet a.k.a. Mr_Destructive | Django Developer | Vim & Linux Enthusiast
  • Location
    Mumbai, India
  • Joined

More fromMeet Rajesh Gor

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp