# [erlang-questions] On OTP rand module difference between OTP 19 and OTP 20

Richard A. O'Keefe <>
Thu Sep 7 02:02:36 CEST 2017

```
On 7/09/17 12:30 AM, Kenji Rikitake wrote:
> Raimo and all:
>
>
> I think the new function name should be
> rand:uniform_non_zero/{1,2}
> because I've rarely seen somethingUPPERCASE
> names in Erlang functions.
> (I might be wrong.)

"nonzero" is one word, so rand:uniform_nonzero/{1,2}
would be better still.
>
> JavaScript math.random(): [0.0, 1.0)
> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
>
> Python random.uniform(a, b): [a, b] (when a <= b)
> https://stackoverflow.com/questions/6088077/how-to-get-a-random-number-between-a-float-range

Ad fontes!  Check the official documentation.
https://docs.python.org/3/library/random.html
says quite explicitly
"Almost all module functions depend on the basic function random(),
which generates a random float uniformly in the semi-open range
[0.0, 1.0)."

The actual source code for random.uniform(a, b) is

def uniform(self, a, b):
"Get a random number in the range
[a, b) or [a, b] depending on rounding."
return a + (b-a) * self.random()

Now of course in exact real arithmetic, if 0 <= u < 1
and a < b then a <= (b-a)*u + a < b.  So they are using
an algorithm that *would* exclude b except for roundoff.
And they are leaving it to users to deal with the
consequences of the numerical error, and weaselling out
of it by blaming the computer.

In any case, Python is a [0,1) example.

> C++ std::uniform_real_distribution<> gen(a, b): [a, b)
> http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution
>
> Ruby 2.4.1 Random class: rand(max): [0.0, max)
> https://ruby-doc.org/core-2.4.1/Random.html
> "When max is a Float, rand returns a random floating point number
>  between 0.0 and max, including 0.0 and excluding max."
>
> R runif(min=0.0, max=1.0): [0.0, 1.0] (See Note)
> https://stat.ethz.ch/R-manual/R-devel/library/stats/html/Uniform.html
> Note: "runif will not generate either of the extreme values
>        unless max = min or max-min is small compared to min,
>        and in particular not for the default arguments."
>
> MySQL 5.7 RAND(): [0.0, 1.0)
> https://dev.mysql.com/doc/refman/5.7/en/mathematical-functions.html#function_rand
>
> PostgreSQL 10 random(): [0.0, 1.0)
> https://www.postgresql.org/docs/10/static/functions-math.html#functions-math-random-table
>
> MS SQL Server: (0.0, 1.0)
> https://docs.microsoft.com/en-us/sql/t-sql/functions/rand-transact-sql
> "Returns a pseudo-random float value from 0 through 1, exclusive."

All of the systems you have mentioned to this point use [0,1)
as the building block (or in the case of R, (0,1).
>
> dSFMT: "[1, 2), [0, 1), (0, 1] and (0, 1)"
> http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/SFMT/#dSFMT
> (dSFMT: SFMT PRNG implementation for double-precision floating point only)

That is to say, it has these functions in the interface:
dsfmt_genrand_close1_open2() => [1,2)    -- their primitive
dsfmt_genrand_close_open() => [0,1)
dsfmt_genrand_open_close() => (0,1]
dsfmt_genrand_open_open() => (0,1)

You *can't* take the range for granted because you have to choose.
The one range it does not offer is [0,1].

The key lesson is that none of these systems offers [0,1] as a
basic building block, and that to the extent that it is possible
to tell, the ones that offer [a,b] as a derived version -- R and
Python -- do so as a sloppy implementation of [a,b).

For what it's worth, my Smalltalk library now has
aRandom
next                             [0,1)
nextNonzero                      (0,1]
nextBetween: a andExclusive: b   [a,b)
nextBetweenExclusive: a and: b   (a,b]
```