How do you generate a random double uniformly distributed between 0 and 1 from C++?
Of course I can think of some answers, but I\'d like to know what the standard pr
As I see it, there are three ways to go with this,
1) The easy way.
double rand_easy(void)
{       return (double) rand() / (RAND_MAX + 1.0);
}
2) The safe way (standard conforming).
double rand_safe(void)
{
        double limit = pow(2.0, DBL_MANT_DIG);
        double denom = RAND_MAX + 1.0;
        double denom_to_k = 1.0;
        double numer = 0.0;
        for ( ; denom_to_k < limit; denom_to_k *= denom )
           numer += rand() * denom_to_k;
        double result = numer / denom_to_k;
        if (result == 1.0)
           result -= DBL_EPSILON/2;
        assert(result != 1.0);
        return result;
}
3) The custom way.
By eliminating rand() we no longer have to worry about the idiosyncrasies of any particular version, which gives us more leeway in our own implementation.
Note: Period of the generator used here is ≅ 1.8e+19.
#define RANDMAX (-1ULL)
uint64_t custom_lcg(uint_fast64_t* next)
{       return *next = *next * 2862933555777941757ULL + 3037000493ULL;
}
uint_fast64_t internal_next;
void seed_fast(uint64_t seed)
{       internal_next = seed;
}
double rand_fast(void)
{
#define SHR_BIT (64 - (DBL_MANT_DIG-1))
        union {
            double f; uint64_t i;
        } u;
        u.f = 1.0;
        u.i = u.i | (custom_lcg(&internal_next) >> SHR_BIT);
        return u.f - 1.0;
}
Whatever the choice, functionality may be extended as follows,
double rand_dist(double min, double max)
{       return rand_fast() * (max - min) + min;
}
double rand_open(void)
{       return rand_dist(DBL_EPSILON, 1.0);
}
double rand_closed(void)
{       return rand_dist(0.0, 1.0 + DBL_EPSILON);
}
Final notes: The fast version - while written in C - may be adapted for use in C++ to be used as a replacement for std::generate_canonical, and will work for any generator emitting values with sufficient significant bits.
Most 64 bit generators take advantage of their full width, so this can likely be used without modification (shift adjustment). e.g. this works as-is with the std::mt19937_64 engine.