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

Raimo Niskanen <>
Fri Sep 8 14:26:28 CEST 2017


To conclude
===========

It would be convenient to have functions in the rand module that
generates on the interval (0.0, 1.0] e.g rand:uniform_nonzero/0
and rand:uniform_nonzero_s/1 or maybe rand:uniform_nz/0
and rand:uniform_nz_s/1.

But since it is very easy to use e.g (1.0 - rand:uniform()) I see
little value in adding them.  Adding hints in the documentation could
suffice.

However, I think we could add functions with the same names and
interval that also has got a different uniformity i.e still uniform,
but not equidistant, instead increasing precison towards 0.  This would
have a greater value.  Such a uniformity would work better for some
suggested algorithms such as Box-Muller.

Ironically, the implementation by Kenji that I changed was a few bits in
that direction i.e used the generators' extra bits over 53 (5 or 11)
for increased precision, but I want to have at least 53 extra bits which I
hope is close enough to infinity.

I have implemented such functions in my own GitHub repo, but ran into
problems with the number distribution that I suspect is caused by
rounding errors in the current implementation of erlang:float/1.

So I will try to find the time to investigate that further...

/ Raimo



On Thu, Sep 07, 2017 at 12:02:36PM +1200, Richard A. O'Keefe wrote:
> 
> 
> On 7/09/17 12:30 AM, Kenji Rikitake wrote:
> > Raimo and all:
> >
> > I got late to follow the thread.
> >
> > 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]
> _______________________________________________
> erlang-questions mailing list
> 
> http://erlang.org/mailman/listinfo/erlang-questions

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB


More information about the erlang-questions mailing list