Fun with floats

I am on a x86_64 machine, in the ocaml-5.1.0 toplevel:

# 1.0 = 1.0 -. min_float;;
- : bool = true

I was surprised by this one.
So, I looked for the smallest float I can get that have the desired behavior:

1.0 = 1.0 -. 0.0000000000000001;;
- : bool = false

So now, I can draw a float in [0, 1[ (“0.0 included, 1.0 excluded”) like this:

let epsilon =  0.0000000000000001;;
let almost_one = 1.0 -. epsilon;;
let rand = Random.float almost_one;;

I also thought about an (recursive but still) ugly solution:
call Random.float 1.0 until you get something <1.0.

You didn’t ask about it, but in case other readers are wondering about it, this is because the precision of floating-point numbers depends on the exponent of the number being represented (this is what makes it “floating” instead of “fixed”), and for 1.0, the maximum precision is smaller than min_float, so that adding or substracting min_float does not have any effect. More generally, this phenomenon is quantified by the “unit in the last place” (ULP): Unit in the last place - Wikipedia.

You can also use Float.pred 1.0.

Cheers,
NIcolas

8 Likes

I did not know about the existence of Float.pred, thanks!

Note that this solution (rejection sampling) is just fine, given that you will never get 1.0 in practice if you call Random.float 1.0. (With the current implementation I believe that the probability for this to happen is 2^{-53}, modulo floating-point approximations).

1 Like