Generate Random Numbers in C++ at Compile Time

Generate random numbers in C++ at compile time

Only constexpr functions and constant expressions may be evaluated at compile time. That rules out <chrono> and <random>.

What you can do is access the __TIME__ preprocessor macro and define your own PRNG composed of one-line, constexpr functions.

generating simple random number with time in c

Static storage duration variables are initialised before any code starts running and they must be initialised with an expression calculable at compile time.

That means no using variables that can't be determined until run-time to initialise them. If you removed the static, the error would disappear but then you're going to re-seed the random number generator every time you call it.

You really should initialise the random seed once before asking for the first random number (as in srand()/rand() from the C standard library), and then use your random function to cycle through the values in the sequence. That could be done with something like:

int rand4 (int numLimit) {
static int randSeed, needsInit = 1;
if (needsInit) { // This bit only done once.
randSeed = time(0);
needsInit = 0;
}
randSeed = (randSeed * 32719 + 3) % 32749;
return (randSeed % numLimit) + 1;
}

A typical implementation of srand()/rand() is along the lines of:

// RAND_MAX assumed to be 32767.
static unsigned long int next = 1;
void srand(unsigned int seed) { next = seed; }
int rand(void) {
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}

in its own source file so that the next seed is hidden from view. This follows the expected behaviour that calling rand() without first calling srand() is the same as if you had called srand (1).


And, based on your comment that you need a certain number of calls to generate all the numbers from 1 to 52, it sounds like you're using this to generate a randomised deck of cards. If that's the case, there's a better way to do it than generating a random number and throwing away those you've already seen.

That solution deteriorates quickly as the size of the remaining deck gets smaller and smaller. For an O(1) time and space solution, use the Fisher-Yates shuffle.

The basic algorithm is to use an unsorted list and simply swap the final element with a randomly chosen one, reducing the list size by one:

dim n[N]                  // gives n[0] through n[N-1]

for each i in 0..N-1: // initialise them to their indexes
n[i] = i // (use i+1 for 1-10 instead of 0-9).

nsize = N // starting pool size
do N times:
i = rnd(nsize) // give a number between 0 and nsize-1
print n[i]
nsize = nsize - 1 // these two lines effectively remove the used number
n[i] = n[nsize]

The numbers generated by that are:

<------ n[] ------>
0 1 2 3 4 5 6 7 8 9 nsize rnd(nsize) output
------------------- ----- ---------- ------
0 1 2 3 4 5 6 7 8 9 10 4 4
0 1 2 3 9 5 6 7 8 9 7 7
0 1 2 3 9 5 6 8 8 2 2
0 1 8 3 9 5 6 7 6 6
0 1 8 3 9 5 6 0 0
5 1 8 3 9 5 2 8
5 1 9 3 4 1 1
5 3 9 3 0 5
9 3 2 1 3
9 1 0 9

How can I generate a random number in c++?

You have to seed it at least 1 change to get random numbers every time you run the file:

#include<iostream>
#include<cstdlib>
#include<ctime>
using namespace std;
int main()
{
srand(time(0));
int random = rand();
cout << "Seed = " << time(0) << endl;
cout << "Random number = " << random << endl;
return 0;
}

Generate unique numbers at compile time

Most people do this with the __COUNTER__ macro. But that's nonstandard, and there's only one for the whole program.

Here is a C++ hack I came up with using templates and overloading which is standard-compliant and supports multiple counters.

Generate random value at compiler time and forever

The C# compiler emits a unique (random) ModuleVersionId (Guid) in every build. This differs even when building from the exact same source.

You may be able to use that as a build token.

As Enigmativity kindly mentioned, you can get to that value using:

this.GetType().Assembly.ManifestModule.ModuleVersionId

Generating random numbers in C

You should call srand() before calling rand to initialize the random number generator.

Either call it with a specific seed, and you will always get the same pseudo-random sequence

#include <stdlib.h>

int main ()
{
srand ( 123 );
int random_number = rand();
return 0;
}

or call it with a changing sources, ie the time function

#include <stdlib.h>
#include <time.h>

int main ()
{
srand ( time(NULL) );
int random_number = rand();
return 0;
}

In response to Moon's Comment
rand() generates a random number with an equal probability between 0 and RAND_MAX (a macro pre-defined in stdlib.h)

You can then map this value to a smaller range, e.g.

int random_value = rand(); //between 0 and RAND_MAX

//you can mod the result
int N = 33;
int rand_capped = random_value % N; //between 0 and 32
int S = 50;
int rand_range = rand_capped + S; //between 50 and 82

//you can convert it to a float
float unit_random = random_value / (float) RAND_MAX; //between 0 and 1 (floating point)

This might be sufficient for most uses, but its worth pointing out that in the first case using the mod operator introduces a slight bias if N does not divide evenly into RAND_MAX+1.

Random number generators are interesting and complex, it is widely said that the rand() generator in the C standard library is not a great quality random number generator, read (http://en.wikipedia.org/wiki/Random_number_generation for a definition of quality).

http://en.wikipedia.org/wiki/Mersenne_twister (source http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html ) is a popular high quality random number generator.

Also, I am not aware of arc4rand() or random() so I cannot comment.

Choose random number distribution at compile time

C++17

I you may use C++17, you can make use of if constexpr(...):

#include <iostream>
#include <random>
#include <type_traits>

template <typename T>
auto get_right_distribution(const T a, const T b) {
if constexpr(std::is_integral<T>::value) {
return std::uniform_int_distribution(a, b);
}
else {
return std::uniform_real_distribution(a, b);
}
}

int main() {
std::random_device rd;
std::mt19937 gen(rd());

auto int_dis = get_right_distribution(1, 6);
std::cout << int_dis(gen) << "\n";

auto float_dis = get_right_distribution(1.F, 6.F);
std::cout << float_dis(gen) << "\n";
}

C++11 & C++14

For C++11 and C++14, you could use a conditional extra template type parameter in your template parameter list to select the return type as well as the distribution.

C++11:

template <typename T,
typename Distribution = typename std::conditional<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>>::type>
Distribution get_right_distribution(const T a, const T b) {
return Distribution(a, b);
}

C++ 14 (return type deduced by auto and using the std::conditional_t helper type short form for std::conditional<...>::type):

template <typename T,
typename Distribution = typename std::conditional_t<
std::is_integral<T>::value,
std::uniform_int_distribution<T>,
std::uniform_real_distribution<T>>>
auto get_right_distribution(const T a, const T b) {
return Distribution(a, b);
}

Generate Random Number Using C

As per details in link What is time(NULL) in C?

You can pass in a pointer to a time_t object that time will fill up with the current time (and the return value is the same one that you pointed to). If you pass in NULL, it just ignores it and merely returns a new time_t object that represents the current time.

time(NULL) simply returns the current time details.

srand() is used for generating a random number.

srand(time(NULL)) just creates a random number, using the current time details as input.



Related Topics



Leave a reply



Submit