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