toZero = rand() % N;
This line of code is giving me Clang-Tidy: rand() has limited randomness. Why is this warning coming up? How can I fix it?
Despite rand() being adequate for very many applications (particularly with extensions like Park-Miller and Bays-Durham shuffling), some code checking tools equate it with a scaled down version of the devil.
Clang-Tidy is warning you that it might not have sufficient properties of randomness for your needs.
Would it be possible to send me a code snippet where Clang-Tidy doesn't warn me while using rand()?
If you are sticking with rand(), you must disable the warning:
toZero = rand() % N; // NOLINT(cert-msc30-c, cert-msc50-cpp)
A better option would be to use the <random> library and functions instead.
One example:
#include <iostream>
#include <random>
#include <type_traits>
// A function to return a seeded random number generator.
inline std::mt19937& generator() {
// the generator will only be seeded once (per thread) since it's static
static thread_local std::mt19937 gen(std::random_device{}());
return gen;
}
// A function to generate integers in the range [min, max]
template<typename T, std::enable_if_t<std::is_integral_v<T>>* = nullptr>
T my_rand(T min, T max) {
std::uniform_int_distribution<T> dist(min, max);
return dist(generator());
}
// A function to generate floats in the range [min, max)
template<typename T, std::enable_if_t<std::is_floating_point_v<T>>* = nullptr>
T my_rand(T min, T max) {
std::uniform_real_distribution<T> dist(min, max);
return dist(generator());
}
int main() {
unsigned N = 100;
std::cout << my_rand(0U, N - 1) << '\n'; // unsigned int:s instead of rand() % N
std::cout << my_rand(-5., 5.) << '\n'; // double's
}
The function rand() is not a C++ function but a C function. It is from stdlib.h, and defined in ISO/IEC 9899 (The C Programming Language).
It does not guarantee a portable level of high randomness.
There are many different implementations possible and no proper quality control in the standard.
A typical implementation of rand() is:
static int next = (int) time();
int rand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
That is, most of the times, rand() is a PRNG and does not use any entropy at all, except maybe for the initial value of next.
So what you should use is the C++11 random library. Here's how it works:
#include <random>
std::default_random_engine generator;
std::uniform_int_distribution<int> distribution(1, 6);
auto dice = std::bind(distribution, generator);
int roll = dice();
DEMO : https://pastebin.run/pzhw6s36g9mf
Notes:
The uniform_int_distribution<int> generates a distribution function that will retrieve numbers from the underlying generator that are evenly distributed between the given range. This is important: Modulo is not an even distribution function. Just doing something like int roll = 1 + nextInt() % 6 is not evenly distributed. (Thanks to Christian Hujer)
Related
I'm trying to generate a random-number sequence with rand().
I have something like this:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int Random(int min, int max)
{
/* returns a random integer in [min, max] */
double uniform; // random variable from uniform distribution of [0, 1]
int ret; // return value
srand((unsigned int)clock());
uniform = rand() / (double)RAND_MAX;
ret = (int)(uniform * (double)(max - min)) + min;
return ret;
}
int main(void)
{
for(int i=0; i<10; i++)
printf("%d ", Random(0, 100));
printf("\n");
return 0;
}
It made different results when executed on macOS v10.14 (Mojave) and Ubuntu 18.04 (Bionic Beaver).
It works on Ubuntu:
76 42 13 49 85 7 43 28 15 1
But not on macOS:
1 1 1 1 1 1 1 1 1 1
Why doesn't it work well on macOS? Is there something different in random number generators?
I'm a Mac user. To generate random numbers I initialise the seed like this:
srand(time(NULL));
Plus, try initialising it in your main.
If reproducible "random" numbers are something you care about, you should avoid the rand function. The C standard doesn't specify exactly what the sequence produced by rand is, even if the seed is given via srand. Notably:
rand uses an unspecified random number algorithm, and that algorithm can differ between C implementations, including versions of the same standard library.
rand returns values no greater than RAND_MAX, and RAND_MAX can differ between C implementations.
Instead, you should use an implementation of a pseudorandom number generator with a known algorithm, and you should also rely on your own way to transform pseudorandom numbers from that algorithm into the numbers you desire. (For many ways to do so, see my page on sampling algorithms. Note that there are other things to consider when reproducibility is important.)
See also the following:
Does Python have a function to mimic the sequence of C's rand()?
Why is the use of rand() considered bad?
How predictable is the result of rand() between individual systems?
rand is obsolete in Mac. Use random() instead.
I would like to go through how rand() and srand() functions are implemented and would like to tweak the code to modify it to my requirements. Where can i find the source code of rand() and srand().
rand and srand are usually implemented as a simple LCG, you can easily write your own (it's few lines of code) without looking for the sources of rand and srand. Notice that, if you need random numbers for "serious" purposes (e.g. cryptography), there are much better RNGs than LCG.
By the way, the C standard itself includes a sample implementation of rand and srand:
static unsigned long int next = 1;
int rand(void) // RAND_MAX assumed to be 32767
{
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
void srand(unsigned int seed)
{
next = seed;
}
It takes a seed as in input argument, usually like follows:-
double result = srand(time(NULL));
and returns a random number that adheres to the probability and hence expected number of occurrences.
from CodeGuru forums:-
void __cdecl srand (unsigned int seed)
{
#ifdef _MT
_getptd()->_holdrand = (unsigned long)seed;
#else /* _MT */
holdrand = (long)seed;
#endif /* _MT */
}
int __cdecl rand (void)
{
#ifdef _MT
_ptiddata ptd = _getptd();
return( ((ptd->_holdrand = ptd->_holdrand * 214013L + 2531011L) >> 16) &
0x7fff );
#else /* _MT */
return(((holdrand = holdrand * 214013L + 2531011L) >> 16) & 0x7fff);
#endif /* _MT */
}
Hope this helps.
The glibc one (used by gcc) is the simple formula:
x = 1103515245 * x + 12345
wrapping around at 232, as shown here. You can just set x as the seed then keep calling a function to evaluate that expression (and update the seed).
But you should be aware the linear congruential generators like this are considered adequate but not ideal.
While the only ideal random number generator would be perfectly random, the Mersenne Twister probably comes closer.
For example, we can use internal rand(), but it is the worst choice:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
float randoms(float min, float max)
{
return (float)(rand())/RAND_MAX*(max - min) + min;
}
int main()
{
srand((unsigned int)time(0));
printf("%f\n",randoms(-100.001, 100.001));
return 0;
}
I've searched, but not found any working example of PCG library for float numbers.
In the answer I would like to share my own experience of using PCG random library to generate float numbers within a fixed range. Previously I've used arc4random library for this goal, but PCG is simpler and has no complicated dependencies.
How to generate float numbers set within a range(?)
Using various random functions can improve the random properties of integers generated. The application of those integers to make a float has other pitfalls not address by OP regardless of the random function. Also see #Serge Ballesta.
The simplistic use of the following risks generating a value outside the range [min...max]
float retval = (float)some_rand()/SOME_RAND_MAX*(max - min) + min;
The 2 conversion of the 2 integers to float incur rounding. float /,*,-,* each can contribute 4 more roundings. Given that min/max may come in many valid combinations, it is prudent to guard against an out-of-range retval
float retval;
assert(min < max); // may want to assert min/max are finite too
do {
retval = 1.0f*some_rand()/SOME_RAND_MAX*(max - min) + min;
} while (!(retval >= min && retval <= max));
return retval;
Note that the setting of FLT_EVAL_METHOD complicates any assessment as some calculations may be conducted as double/long double.
Potential losses of desired random properties:
The use of pcg32_random_r() versus rand() does provide numbers with more attractive integer random properties, yet those improved attributes are reduced with casual floating-point code.
(Assume binary32 for float)
Consider how the following can uniformly generate values in the range [0...224] yet values larger than that, it will be only even numbers. It becomes spottier with larger numbers up to (float)UINT32_MAX. This would be acceptable for another function that was now to return that value, but the scaling of *(max - min) + min redistributes those values in a way that can become very non-uniform.
(float)pcg32_random_r(...);
A simple way to address some of these short comings is to use higher precision like double math within float randoms(float min, float max), yet that approach does not help with long double randomsL(long double min, long double max)
You PCG will generate some number of random bits. Let's say that's 32. A double precision float has 53 bits of significand, so you'll need more than one call. So, call the function twice, and pack the two calls into a 64-bit integer:
int64_t x = (pcg32() << 32) | pcg32();
Then divide that integer down to the desired range (this is the signed -100...100 version):
double r = ((double)x * 100.0) / 9223372036854775808.0; // 2**63
// main.c
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
// PCH library headers
#include "pcg_variants.h"
#include "entropy.h" // Wrapper around /dev/random
int main(int argc, char** argv)
{
pcg32_random_t rng;
// Seed with external entropy
uint64_t seeds[2];
entropy_getbytes((void*)seeds, sizeof(seeds));
pcg32_srandom_r(&rng, seeds[0], seeds[1]);
for (int i = 0; i < 10; ++i)
{
uint32_t random_unsigned_integer = pcg32_random_r(&rng);
float max = 100.001;
float min = -100.001;
float q = (float)(random_unsigned_integer)/((float)UINT32_MAX)*(max - min) + min;
// Shows 10 float numbers in specified range.
printf("%.6f\n", q);
}
return 0;
}
Compile:
gcc -std=c11 -o pcg_float main.c
I'm trying to generate a simple random number in C with the raspberry pi. The code compiles fine but when running it the number is not random, its 384 each time.
Where am I going wrong?
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
printf ("Random number generator\n") ;
int x = (rand() % 1000) + 1;
printf("%d\n", x);
return 0 ;
}
You need to seed the random number generator with some naturally random value like the current time. Something like:
srand (time(NULL));
Update: note that you will need to add an include for the time library if you use the example above:
include <time.h>
Use this function to generate random value. also make sure to add the library include <time.h>.
// Random value will be from 0 to #
int GenerateRandomInt (int MaxValue)
{
unsigned int iseed = (unsigned int)time(NULL); //Seed srand() using time() otherwise it will start from a default value of 1
srand (iseed);
int random_value = (int)((1.0 + MaxValue) * rand() / ( RAND_MAX + 1.0 ) ); //Scale rand()'s return value against RAND_MAX using doubles instead of a pure modulus to have a more distributed result.
return(random_value);
}
How can I implement the rand() C++ function in mikroC?
I tried rand() but does not work... I don't know how to resolve this
If your C implementation conforms to C89, it should include a working rand() — maybe you forgot to include <stdlib.h>?
If not, it is trivial to write your own rand, as long as you don't require very high quality of generated numbers, which you shouldn't for the purposes of TETRIS. This tiny implementation is promoted by POSIX as an option for programs that need to repeat the same sequence of pseudo-random numbers across architectures:
static unsigned long next = 1;
/* RAND_MAX assumed to be 32767 */
int myrand(void) {
next = next * 1103515245 + 12345;
return((unsigned)(next/65536) % 32768);
}
void mysrand(unsigned seed) {
next = seed;
}
It will not give you great pseudo-randomness, but it won't be worse than many real-life implementation of rand(), either.