Jump to page: 1 2
Thread overview
Random double
Apr 23, 2013
qznc
Apr 23, 2013
Ali Çehreli
Apr 23, 2013
qznc
Apr 23, 2013
Ali Çehreli
Apr 24, 2013
qznc
Apr 25, 2013
Ali Çehreli
Apr 23, 2013
bearophile
Apr 24, 2013
qznc
Apr 24, 2013
Ivan Kazmenko
Apr 24, 2013
Andrea Fontana
Apr 24, 2013
Ivan Kazmenko
Apr 24, 2013
Andrea Fontana
Apr 24, 2013
Ivan Kazmenko
Apr 24, 2013
qznc
Apr 24, 2013
Ivan Kazmenko
Apr 24, 2013
Ivan Kazmenko
April 23, 2013
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?
April 23, 2013
On 04/23/2013 07:43 AM, 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);

Since double.max is a valid double value, you may want to call uniform with a closed range:

  uniform!"[]"(-double.max, double.max)

However, that still produces double.inf. :)

> Should that be considered a bug?

I would say yes, it is a bug.

> Nevertheless, any ideas how to work around that issue?

Floating point numbers have this interesting property where the number of representable values in the range [double.min_normal, 1) is equal to the number of representable values in the range [1, double.max]. The number line on this article should help with what I am trying to say:

  http://dlang.org/d-floating-point.html

So, to workaround this problem I would suggest simply using the following range:

        uniform(-1.0, 1.0);

One benefit is, now the range is open ended: You don't need to provide !"[)" to leave 1 out, because it is the default. On the other hand, the width of the range is now 2.0 so you must keep that in mind when you scale the value:

Additionally, note that the random numbers in the range between [-double.min_normal, double.min_normal] and outside of those may have a different distribution. Test before using. :) (I have no experience with floating point random numbers.)

Ali

April 23, 2013
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?
April 23, 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

April 23, 2013
qznc:

> I want to generate a random "double" value, excluding wierdos like NaN and Infinity. However, std.random.uniform seems to be useless.

Can you explain why you need uniform doubles in their whole range? I think I have never had to generate them so far. Maybe for a unittest?

Also note by their nature doubles are not equally spread across the line of Reals, so getting a truly uniform distribution is hard or impossible.

Bye,
bearophile
April 24, 2013
Tue, 23 Apr 2013 22:59:41 +0200: bearophile wrote

> qznc:
> 
>> I want to generate a random "double" value, excluding wierdos like NaN and Infinity. However, std.random.uniform seems to be useless.
> 
> Can you explain why you need uniform doubles in their whole range? I think I have never had to generate them so far. Maybe for a unittest?

Good guess. :)

I want to port QuickCheck. The core problem is: Given a type T, generate a random value.

https://bitbucket.org/qznc/d-quickcheck/src/ eca58bb97b24cedd6128cdda77bbebeaf1689956/quickcheck.d?at=master

> Also note by their nature doubles are not equally spread across the line of Reals, so getting a truly uniform distribution is hard or impossible.

It also raises the question what uniform means in the context of floating point. Uniform over the numbers or uniform over the bit patterns?
April 24, 2013
Tue, 23 Apr 2013 13:49:48 -0700: Ali Çehreli wrote

> 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:


Interesting. Why [-0.5,0.5], though? I would have expected [-1.0,1.0] from Clugston's article.

http://dlang.org/d-floating-point.html
April 24, 2013
On Wednesday, 24 April 2013 at 06:37:50 UTC, qznc wrote:
> It also raises the question what uniform means in the context of floating point. Uniform over the numbers or uniform over
> the bit patterns?

I'd like to mention that there's no such mathematical object as "uniform distribution on [0..+infinity)".  On the other hand, a (discrete) uniform distribution of the bit pattern, or restricted bit pattern (that is, no special values), is of course valid.  A "random positive double" as a bit pattern most closely resembles exponential distribution I think.
April 24, 2013
On Wednesday, 24 April 2013 at 06:56:44 UTC, Ivan Kazmenko wrote:
> On Wednesday, 24 April 2013 at 06:37:50 UTC, qznc wrote:
>> It also raises the question what uniform means in the context of floating point. Uniform over the numbers or uniform over
>> the bit patterns?
>
> I'd like to mention that there's no such mathematical object as "uniform distribution on [0..+infinity)".

... you neither can choose a random real number in any interval ...

April 24, 2013
On Wednesday, 24 April 2013 at 10:26:19 UTC, Andrea Fontana wrote:
>> I'd like to mention that there's no such mathematical object as "uniform distribution on [0..+infinity)".
>
> ... you neither can choose a random real number in any interval ...

... but that is at least valid mathematically, albeit achievable only approximately on a computer.  On the other hand, an infinite case, even if it would be possible, won't be practical anyway since with probability 1, the result would require more bits to store than available on any modern hardware.
« First   ‹ Prev
1 2