Some considerations about random numbers generation. GReaper is right pointing to the fact that the *linear congruential random number generator* is problematic. The lower bits tends to be less random. Notice that this is a characteristic of this specific PRNG and the method using floating-point is a way to mitigate the problem obtaining a value between 0.0 and 1.0, and multiplying by the desired range. But there is a faster way: Use the *upper* bits instead.

This expression:

Code:

int index = (int)((rand()/(double)RAND_MAX)*48 + 0.5);

Could be writen using, entirely, integer operations like:

Code:

int index = (rand() >> 25) % 50;

Why 25 bits right shift? Because we need values between 0 and 2⁶ (64, the upper 6 bits -- more bits will be less random!), but rand() always returns an unsigned value (it is usual RAND_MAX to have the most significant bit zeroed). And for i386 and x86-64 modes it is usual RAND_MAX to be 31 bits long...

The second function is faster the the first (no floating point required and just one division)...

**Hardware RNG:**

There is a faster way, and more random!

If you are using Intel or AMD processors and want a "truly random" number (not "pseudo"), Modern architectures (since Haswell, for instance) has an internal diode to measure "noise" caused by temperature. Using this "quantum effect" we have a "true" RNG (almost!). And there is an instruction to get these random values generated by the CPU: RDRAND.

There are two advantages: RDRAND is faster then rand() and will return 16, 32 or 64 bits of truly random number (not 31).

Except by the intrinsic function __cpuid(), I prefer to implement RDRAND in assembly (there is an instrinsic __randNN_step() available in immintrin.h). NN is 16, 32 or 64:

Code:

#include <stdlib.h>
#include <time.h>
#if defined( __x86_64__ ) || defined( __i386__ )
#include <cpuid.h>
static int supports_rdrand = 0;
// This will be called before main()...
__attribute__ ( ( constructor ) )
void test_rdrand_support ( void )
{
# ifdef __x86_64__
unsigned long long flags;
# else
unsigned int flags;
# endif
unsigned int a, b, c, d;
__asm__ __volatile__ (
# ifdef __x86_64__
"pushfq; popq %0"
# else
"pushfl; popl %0"
# endif
: "=g" ( flags ) );
// supports cpuid?
supports_rand = 0;
if ( flags & ( 1U << 21 ) )
supports_rdrand = 1;
if ( supports_rdrand )
{
__cpuid ( 1, a, b, c, d );
supports_rdrand = !! ( c & ( 1U << 30 ) );
if ( supports_rand )
return;
}
srand ( time ( NULL ) );
}
int getrand ( void )
{
if ( supports_rdrand )
{
int rnd;
__asm__ __volatile__ (
"1: rdrand %0; jnc 1b" : "=r" ( rnd )
);
return rnd;
}
else
return rand();
}
#else
# define getrand(...) rand()
#endif