Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generate uniformly random float which can return all possible values

An easy way to generate a random float64 in [0,1) is by generating a uniformly random int in [0,2⁵³) and dividing it by 2⁵³. This is essentially what rand.Float64() is doing. However, not all possible float64 values between 0 and 1 can be generated this way: if the value is lower than 2⁻⁴ for example, the 4 last bits of the significand are always going to be 0. Or, put more simply, the naive method always returns multiples of 2⁻⁵³, and not all floating point numbers between 0 and 1 are multiples of 2⁻⁵³.

How do you generate a uniformly random float64 such as every possible value has a chance of being returned? (Here, uniformly random means over the real interval [0,1): conceptually, I want to pick a uniformly random real number between 0 and 1 and return the closest float.)

For context, I need this because I'm implementing this paper and the assumption "all possible values between 0 and 1 are represented" is essential for the result to hold.

like image 984
Ted Avatar asked Nov 13 '18 08:11

Ted


People also ask

Which random method is used to return float value?

The nextFloat() method is used to get the next pseudorandom, uniformly distributed float value between 0.0 and 1.0 from this random number generator's sequence.

How do you generate uniformly distributed random numbers?

The Uniform Random Number block generates uniformly distributed random numbers over an interval that you specify. To generate normally distributed random numbers, use the Random Number block. Both blocks use the Normal (Gaussian) random number generator ( 'v4' : legacy MATLAB® 4.0 generator of the rng function).

How do you generate a random float in Python?

Use a random. random() function of a random module to generate a random float number uniformly in the semi-open range [0.0, 1.0) . Note: A random() function can only provide float numbers between 0.1. to 1.0. Us uniform() method to generate a random float number between any two numbers.


2 Answers

Porting this code (suggested in Severin's answer) is a possible option.

I think that it is equivalent to first generate the significand bits (by generating a random float in [1,2)), and then choose the exponent from a geometric distribution (it has a 0.5 chance of being -1, 0.25 of being -2, etc.).

// uniform returns a uniformly random float in [0,1).
func uniform() float64 {
  sig := rand.Uint64() % (1 << 52)
  return (1 + float64(i)/(1<<52)) / math.Pow(2, geometric())
}

// geometric returns a number picked from a geometric
// distribution of parameter 0.5.
func geometric() float64 {
  b := 1
  for rand.Uint64()%2 == 0 {
     b++
  }
  return b
}

We can probably make geometric() faster by using one of the LeadingZeros* functions from the bits package instead of doing one coin flip per bit.

like image 126
Ted Avatar answered Oct 02 '22 23:10

Ted


Well, standard way, I believe, is to generate up to 1074bits integer and map it to the double. Beware, that your RNG should have internal state at least 1074bits long.

Reference implementation: http://xoshiro.di.unimi.it/random_real.c

Discussion about it: http://xoshiro.di.unimi.it/

Another good link: https://lemire.me/blog/2017/02/28/how-many-floating-point-numbers-are-in-the-interval-01/

like image 34
Severin Pappadeux Avatar answered Oct 02 '22 23:10

Severin Pappadeux