On Sat, Dec 21, 2019 at 11:29:20PM +0000, Alexander Nasonov wrote:
> Ingo Schwarze wrote:
> > Looking at our code in lib/libc/stdlib/drand48.c, i conclude that
> > drand48(3) does return 0.0 with a probability of 2^-48.
> 
> I looked at the code too and I have some comments.
> 
> > More generally, the function returns a uniform distribution of
> > numbers from the set {2^-48 * n | n integer and 0 <= n < 2^48}.
> 
> You don't need three ldexp calls to compose 2^-48 * n:
> 
>       uint64_t n = (uint64_t)xseed[2] << 32 | xseed[1] << 16 | xseed[0];
>       return ldexp((double)n, -48);
> 
> > Talking about loading bits into the mantissa and adjusting the
> > exponent feels mildly confusing, given that the distribution is
> > simply uniform over a fixed finite set.  I'm not sending a patch
> > because i never looked at how floating point representation works
> > internally, so i would likely only make matters worse.
> 
> Not sure if you wanted to patch the man page or the code.
> 
> If the latter, take a binary representation of 1.0 and replace 52
> least significant bits with (pseudo)random bits then subtract 1.0.
> 
>       double d = 1.0;
>       uint64_t u = 0;
>       memcpy(&u, &d, sizeof(d));
>       u |= n << 4; /* scale 48 bits to 52 bits, n is from the previous 
> snippet */
>       memcpy(&d, &u, sizeof(u));
>       return d - 1.0;
> 
> It will only work with IEEE 754 compliant doubles, though.

A very clear way to generate an equidistributed floating point number in
the range [0.0, 1.0) given a number n in the range [0, 2^48-1] is simply:

    return n * 0x1.0p-48

Requiring only C99 and <stdint.h>.

> 
> -- 
> Alex

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB

Reply via email to