How can C/C++'s rand() generate random numbers so quickly? - c++

My understanding is that a pseudo-random number generator basically just takes some number (the seed), hashes it with a bunch of XORs and bitshifts, and then spits out a really long number from which a remainder can be retrieved to get your "random" number.
Now, usually you'd use time(NULL) as the seed for rand() in C/C++. However, time(NULL) only increments every second, not every millisecond. So how, then, can I for loop over rand() a thousand times in less than one second and still get different numbers as outputs if the seed is still the same time(NULL) value?

rand() uses the previous random value as the new seed on subsequent calls. This is why a unique random sequence of values will be generated when you start with a different seed value.

A pseudo number generator outputs a deterministic series of numbers in a certain range that are supposed to look random.
The time(NULL) is the so called seed of the RNG and tells it, where in the series to start. You should only do this once per program.
By the way, rand() is not modern C++. See here for why and what to do instead.

It's common for C / C++ compilers to use a linear congruential generator for rand().

Related

The meaning of srand()

I don't understand the meaning of srand() in <time.h> to create a random number.
Here is my code:
/* srand example */
#include <stdio.h> /* printf, NULL */
#include <stdlib.h> /* srand, rand */
#include <time.h> /* time */
int main ()
{
printf ("First number: %d\n", rand()%100);
srand (time(NULL));
printf ("Random number: %d\n", rand()%100);
srand (1);
printf ("Again the first number: %d\n", rand()%100);
return 0;
}
and the results are:
First number: 41
Random number: 13
Again the first number: 41
Why is the result of srand(1) different from srand(2)?
Why does the result of srand(1) or srand(2) keep appearing again and again?
And why do I have to use srand(time(NULL)) in order to create a dynamic random number?
If you look at the docs:
Seeds the pseudo-random number generator used by std::rand() with the value seed.
rand() has some internal state that it keeps from one call to the next. The function is deterministic - but we can view its output as pseudorandom. So the value produced by:
srand(1);
rand();
will always be the same for a given implementation. That's why the notes state that:
Generally speaking, the pseudo-random number generator should only be seeded once, before any calls to rand(), and the start of the program. It should not be repeatedly seeded, or reseeded every time you wish to generate a new batch of pseudo-random numbers.
srand() uses a seed to determine what the number will be. srand() always produces the same number when given the same seed. If you don't give it a seed, then it uses something in the system to determine what the seed will be, and this makes the numbers appear random - the seed is constantly changing. srand(1) will always be the same.
The function rand() (and most other “random”
sources1) is
an implementation of a “pseudo-random number generator”.
The numbers it generates are not random at all, but simply numbers in a
very long sequence of discreet values; the sequence is designed so that
successive numbers appear random, according to some suitable definition
of random.
The function srand() simply sets a starting point in this sequence.
[1] Most OS do have some source of truly random numbers, such as the
file /dev/random on Unix systems. They can be very slow for more than
a few bytes, however. There main use is to seed a PRNG.
Hmm, you need better understanding of how Pseudo-Random Number Generators (PRNGs) work. The word "Pseudo" is very important: actually it is very hard to generate really random number, it is easier to take it once (like time in seconds) then compute other values based on it.
I.e. Linear Congruential Generator which is often used for libc rand() calculates random number based on previous value, so:
First X is set by srand()
What's usually called a random number generator is actually a pseudo-random number generator. This typically means that you can generate the same random sequence if you provide the "key" to that sequence, referred to as the "seed". This is very useful when you wish to test your algorithm that is based on randomization, and you need to ensure repeatable results.
If you do not "seed" your Random number generator, it is seeded with 1
Seed values are integers that define the exact sequence of pseudo-random numbers, but there's no way of knowing ahead of time what sequence it will be and there's no way of tweaking a sequence by slightly changing the seed. Even the tiniest change in seed value will result in a radically different random sequence.

can rand() be used to generate predictable data?

My goal is generate 2D or 3D geometry without having to store it on disk, so my goal is to have any sort of function than generate the same values according to a small seed. I don't mean to seek random values, but if the same "random" garbage data is returned when given the same seed, that's something I'm looking for.
If I give srand() the same integer, I get the same sequence out of rand(). Is that an intended feature? If not, are there known standard functions designed to do the same thing?
Although I tried this on ideone and on my computer and I get different results, I can understand that those function's implementations are not described, so that explains it.
If I give srand() the same integer, I get the same sequence out of rand(). Is that an intended feature?
Yes, see 7.20.2.2:
7.20.2.2 The srand function
[...] Description
The srand function uses the argument as a seed for a new sequence of pseudo-random
numbers to be returned by subsequent calls to rand. If srand is then called with the
same seed value, the sequence of pseudo-random numbers shall be repeated.
However, that's only true for the same implementation of srand/rand. Another implementation might not use the same algorithm, and therefor won't produce the same sequence.
If not, are there known standard functions designed to do the same thing ?
Well, the functions are standard, but only in their behaviors, not the actual values (see implementation remark above). You're better off by using a specific generator from the C++11 predefined random number generators, since they're standardized.
"If I give srand() the same integer, I get the same sequence out of
rand(). Is that an intended feature ?"
Yes.
If you seed the same random number generator with the same seed, it will produce the same result.
Standard library rand and all it's variants are usually implemented as Linear congruential generators. They are not truly random, and perhaps better referred to as psuedo-random.
You probably saw different results on different machines because either they were using different psuedo-random number generation algorithms or you weren't supplying a fixed seed in which case the current system time is often the default seed.
If you need a fixed set of psuedo-random data, then generate it once and store it.
The answer is yes, you get a repeatable sequence, if you always use the same implementation and the same seed, though it might be ill-advised due to possibly poor quality of rand().
Better use the C++ random number framework in <random> though. It not only allows reproducible sequences across implementations, it also supplies all you need to reliably get the distribution you really want.
Now to the details:
The requirements on rand are:
Generates pseudo-random numbers.
Range is 0 to RAND_MAX (minimum of 32767).
The seed set by srand() determines the sequence of pseudo-random numbers returned.
There is no requirement on what PRNG is implemented, so every implementation can have its own, though Linear Congrueantial Generators are a favorite.
A conforming (though arguably useless) implementation is presented in this dilbert strip:
http://dilbert.com/strips/comic/2001-10-25/
Or for those who like XKCD (It's a perfect drop-in for any C or C++ library ;-)):
For completeness, the standard quotes:
7.22.2.1 The rand function
The rand function computes a sequence of pseudo-random integers in the range 0 to
RAND_MAX.
[...]
The value of the RAND_MAX macro shall be at least 32767.
7.22.2.2 The srand function
The srand function uses the argument as a seed for a new sequence of pseudo-random
numbers to be returned by subsequent calls to rand. If srand is then called with the
same seed value, the sequence of pseudo-random numbers shall be repeated. If rand is
called before any calls to srand have been made, the same sequence shall be generated
as when srand is first called with a seed value of 1.
If you seed the random number generator with the same value, it will produce the same result. You saw different results on different machines because they were (probably) using different random number generation algorithms.

Generate random number between 0 and 1

Simple question but difficult to me. I want to generate uniformly distributed random numbers between 0 and 1, how can I do it? In matlab I am using rand, in C++ rand() returns integers.
Since C++11, use std::uniform_real_distribution
maybe you can use the RAND_MAX constant to divide the randomly generated integer
It really depends on how random you need the numbers to be. Generally, if I don't care about how random it is I will just use rand and divide by MAX_RAND (I bet matlab's rand is better than c's rand).
However, most of what I have done has required a better random number generator than the c function rand, and I don't need it to be cryptographically secure. In this case I use a mersenne twister class (http://www.bedaux.net/mtrand/) which has seemed to work better for the simulated annealing and monte carlo simulations that I sometimes find myself doing.
Also with this class, there is a way to get a random int32 and a radom double (between 0 and 1) out.

Understanding the rand() operation

At http://www.cplusplus.com/reference/clibrary/cstdlib/rand/ , I read the following : This algorithm uses a seed to generate the series, which should be initialized to some distinctive value using srand.
What does seed mean and how does rand() use seed to generate the series?
rand() uses a so-called pseudo-random number generator. It generates not really random numbers but a deterministic sequence that appears to look random enough and satisfy some statistical properties. The seed is essentially the starting value of that sequence; given the same seed, the PRNG will always produce the same sequence. That is why you often seed with something that is not too deterministic, e.g. the current time (although that fails if you re-seed the PRNG in a tight loop or run the program fast enough in succession or parallel).
In most cases the PRNG in C is a simple linear congruential generator. It calculates the next number in a sequence with the following equation:
a and b here are values that have to be chosen with care to avoid horrible results. For example, for obvious reasons 2 is a very very bad choice for a. c just reduces the number to a certain range and is often a power of two. The seed simply supplies the 0th value.
Very crudely, it is something like:
int rand() {
return last_random_val =
((last_random_val * 1103515245) + 12345) & 0x7fffffff);
}
void srand(int seed) {
last_random_val = seed;
}
And the last_random_val is set to the seed when you call srand(). Hence, for the same seed, same sequence of numbers are generated.

Better random algorithm?

I'm making a game in C++ and it involves filling tiles with random booleans (either yes or no) whether it is yes or no is decided by rand() % 1. It doesn't feel very random.
I'm using srand with ctime at startup, but it seems like the same patterns are coming up.
Are there any algorithms that will create very random numbers? Or any suggestions on how I could improve rand()?
True randomness often doesn't seem very random. Do expect to see odd runs.
But at least one immediate thing you can do to help is to avoid using just the lowest-order bit. To quote Numerical Recipes in C:
If you want to generate a random integer between 1 and 10, you should always do it by using high-order bits, as in
j = 1 + (int) (10.0 * (rand() / (RAND_MAX + 1.0)));
and never by anything resembling
j = 1 + (rand() % 10);
(which uses lower-order bits).
Also, you might consider using a different RNG with better properties instead. The Xorshift algorithm is a nice alternative. It's speedy and compact at just a few lines of C, and should be good enough statistically for nearly any game.
The low order bits are not very random.
By using %2 you are only checking the bottom bit of the random number.
Assuming you are not needing crypto strength randomness.
Then the following should be OK.
bool tile = rand() > (RAND_MAX / 2);
The easiest thing you can do, short of writing another PRNG or using a library, would be to just use all bits that a single call to rand() gives you. Most random number generators can be broken down to a stream of bits which has certain randomness and statistical properties. Individual bits, spaced evenly on that stream, need not have the same properties. Essentially you're throwing away between 14 and 31 bits of pseudo-randomness here.
You can just cache the number generated by a call to rand() and use each bit of it (depending on the number of bits rand() gives you, of course, which will depend on RAND_MAX). So if your RAND_MAX is 32768 you can use the lowest-order 15 bits of that number in sequence. Especially if RAND_MAX is that small you are not dealing with the low-order bits of the generator, so taking bits from the high end doesn't gain you much. For example the Microsoft CRT generates random numbers with the equation
xn + 1 = xn · 214013 + 2531011
and then shifts away the lowest-order 16 bits of that result and restricts it to 15 bits. So no low-order bits from the generator there. This largely holds true for generators where RAND_MAX is as high as 231 but you can't count on that sometimes (so maybe restrict yourself to 16 or 24 bits there, taken from the high-order end).
So, generally, just cache the result of a call to rand() and use the bits of that number in sequence for your application, instead of rand() % 2.
Many pseudo-random number generators suffer from cyclical lower bits, especially linear congruential algorithms, which are typically the most common implementations. Some people suggest shifting out the least significant bits to solve this.
C++11 has the following way of implementing the Mersenne tittie twister algorothm. From cppreference.com:
#include <random>
#include <iostream>
int main()
{
std::random_device rd;
std::mt19937 gen(rd());
std::uniform_int_distribution<> dis(1, 6);
for (int n=0; n<10; ++n)
std::cout << dis(gen) << ' ';
std::cout << '\n';
}
This produces random numbers suitable for simulations without the disadvantages of many other random number generators. It is not suitable for cryptography; but cryptographic random number generators are more computationally intensive.
There is also the Well equidistributed long-period linear algorithm; with many example implementations.
Boost Random Number Library
I have used the Mersenne Twister random number generator successfully for many years. Its source code is available from the maths department of Hiroshima Uni here. (Direct link so you don't have to read Japanese!)
What is great about this algorithm is that:
Its 'randomness' is very good
Its state vector is a vector of unsigned ints and an index, so it is very easy to save its state, reload its state, and resume a pseudo-random process from where it left off.
I'd recommend giving it a look for your game.
The perfect way of Yes or No as random is toggling those. You may not need random function.
The lowest bits of standard random number generators aren't very random, this is a well known problem.
I'd look into the boost random number library.
A quick thing that might make your numbers feel a bit more random would be to re-seed the generator each time the condition if(rand() % 50==0) is true.
Knuth suggests a Random number generation by subtractive method. Its is believed to be quite randome. For a sample implementation in the Scheme language see here
People say lower-order bits are not random. So try something from the middle. This will get you the 28th bit:
(rand() >> 13) % 2
With random numbers to get good results you really need to have a generator that combines several generators's results. Just discarding the bottom bit is a pretty silly answer.
multiply with carry is simple to implement and has good results on its own and if you have several of them and combine the results you will get extremely good results. It also doesn't require much memory and is very fast.
Also if you reseed too fast then you will get the exact same number. Personally I use a class that updates the seed only when the time has changed.