Random number in (0,1]

I want a random Float64 in the interval (0,1].
I understand rand() returns a number in [0,1).
Should I just use 1-rand() ?

1 Like

is rand() not more like (0,1)? And how much does [0,1) matter vs (0,1]? For most numerical problems, I assume the distinct makes no different what-so-ever in practice.

That’s a nice and quick solution. You can also check for 1 and make it into a 0, eg

rand(Float64) |> x -> iszero(x) ? one(x) : x

You should not use 1.0 - rand().
The density of Float64s (how many occur within a subspan) varies within [0.0,1.0].


(source: https://ridiculousfish.com/blog/posts/float.html)

fig1
(source: http://jasss.soc.surrey.ac.uk/9/4/4.html)

for a single random Float64 in (0.0, 1.0]

randfloat = rand()
if randfloat === 0.0
    randfloat = 1.0
end

for n of them

zerosasones(x) = ifelse(x === 0.0, 1.0,  x) 
randfloats = zerosasones.(rand(n))
2 Likes

I am not sure how that is relevant, AFAIK rand accounts for that and the result is uniform.

The density is varying but rand() does sample from it uniformly as it actually samples from [1,2[ and subtracts 1.0.

This is equivalent to running 2.0-rand(Random.CloseOpen12()) which avoids this subtraction.

You can check it by running:

julia> function t(m1, m2)
           x = 1.0 - rand(m1)
               y = 2.0 - rand(m2, Random.CloseOpen12())
                   x == y
                   end
t (generic function with 2 methods)

julia> m1, m2 = MersenneTwister(100), MersenneTwister(100);

julia> all(t(m1,m2) for i in 1:10^8)
true

The key thing here is that on [1,2[ interval all Float64 are uniform. You can check that eps for any value in [1,2[ range is the same. as well as the difference between x and nextfloat(x) in this range.

In other words if you look at http://jasss.soc.surrey.ac.uk/9/4/4.html image [1,2[ just happens to be one subsegments that is uniform on it.

Actually on https://ridiculousfish.com/blog/posts/float.html it is shown on this picture:
image

10 Likes
using StatsBase: skewness

rs01 = rand(n)
rs10 = 1.0 .- rs01

skewness(rs01) == -skewness(rs10)

You are demonstrating numerical error (after correcting to rs10 = 1.0 .- rs01, which makes it run).

I am demonstrating skewness in small random samples and that it swaps signs using 1.0 .- rand()

More to the point, a uniform random number generator returning values in [0.0, 1.0) is used internally in simulation code that requires random variates from some specific non-unform distribution, often also in [0.0, 1.0). Once that happens, using one minus random variate probably maps some distinct smaller numbers together as they cross power of 2 bounds.

What you show is important, but it is unrelated to random number generation. If you take any vector x (random or not) you will get the same result. What I understand @Tamas_Papp says is that skewness(1.0 .- x) == skewness(x) will be often false due to roundoff errors.

The swapping of signs in skewness is not a function of roundoff errors, it is a function of the mirroring.

This is correct - if you have a non-uniform distribution on [0,1[ then taking 1 minus it might hit the non uniformity problem.

No, as s(x) = -s(A-x) is an identity for s being skewness, and A a constant. What you are showing is that this does not hold in practice, because of numerical error. That is orthogonal to this discussion. Cf eg

julia> x = rand(10^9);

julia> A = 100
100

julia> sum(x) + A == sum(x .+ A)
false

and various similar examples.

I am referring to:

julia> using Random

julia> Random.seed!(100);

julia> x = rand(100000);

julia> skewness(1.0 .- x) == -skewness(x)
false

and you see that the sign is swapped but the values are not exactly opposite - they are only approximately opposite.

this is getting away from itself – try the same thing using Float16 rands, Float16(skewness(x)) and 1000 samples. I know that floating point errors accrue – no argument there. :wink:

coding to the internal workings of rand() … kinda iffy for FAA system simulations

So you’re saying that if you take 1.0 - rand() then many of the small floats, close to zero, can never be selected, since eps is larger close to 1.0? Those small numbers just become inaccessible to the algorithm.

1 Like

Yes. You can theoretically get 0 and the next theoretically possible value is eps().