Random double

Ali Çehreli acehreli at yahoo.com
Tue Apr 23 13:49:48 PDT 2013


On 04/23/2013 11:55 AM, qznc wrote:> Tue, 23 Apr 2013 16:43:14 +0200: 
qznc wrote
 >
 >> I want to generate a random "double" value, excluding wierdos like NaN
 >> and Infinity. However, std.random.uniform seems to be useless. I tried
 >> things like
 >>
 >>     std.random.uniform( double.min, double.max);
 >>     std.random.uniform(-double.max, double.max);
 >>     std.random.uniform(0.0, double.max);
 >>
 >> However, I just get Inf values. :(
 >>
 >> I assume this is due to floating point computation within uniform, which
 >> easily becomes Inf, if you come near the double.max boundary. Should
 >> that be considered a bug? Nevertheless, any ideas how to work around
 >> that issue?
 >
 > Using a union seems to be a good workaround:
 >
 >    union foo { ulong input; double output; }
 >    foo val = void;
 >    do {
 >    	val.input = uniform(ulong.min, ulong.max);
 >    } while (val.output == double.infinity
 >          || val.output == -double.infinity
 >          || val.output != val.output);
 >    return val.output;
 >
 > Maybe the implementation of uniform should use a similar trick?

Unfortunately, that will not produce a uniform distribution. The results 
will mostly be in the range [-0.5, 0.5]. The lower and higher values 
will have half the chance of the middle range:

import std.stdio;
import std.random;

double myUniform()
{
     union foo { ulong input; double output; }
     foo val = void;
     do {
         val.input = uniform(ulong.min, ulong.max);
     } while (val.output == double.infinity
              || val.output == -double.infinity
              || val.output != val.output);
     return val.output;
}

void main()
{
     size_t[3] bins;

     foreach (i; 0 .. 1_000_000) {
         size_t binId = 0;
         auto result = myUniform();

         if (result > -0.5) { ++binId; }
         if (result > 0.5)  { ++binId; }

         ++bins[binId];
     }

     writeln(bins);
}

Here is an output of the program:

[250104, 499537, 250359]

The first value is "less than -0.5", the second one is "between -0.5 and 
0.5", and the third one is "higher than 0.5".

Ali



More information about the Digitalmars-d-learn mailing list