On OTP rand module difference between OTP 19 and OTP 20

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
52 messages Options
123
Reply | Threaded
Open this post in threaded view
|

On OTP rand module difference between OTP 19 and OTP 20

Kenji Rikitake-4
I finally reviewed OTP rand module change between 19.3 and 20.0.
While most of users won't recognize the changes,
the details are considerably different.

A good news is that if you're not aware of the PRNG algorithm
you can keep the code untouched. The new default algorithm
works ok and even better than the OTP 19 with less bugs.

On the other hand, if you explicitly specify the algorithm in rand:seed/1,
you are suggested to use a newly-available algorithms
described in the rand module manual of OTP 20.0. Actually
all the old (OTP 18 and 19) algorithms are now deprecated.
See rand module manual of OTP 20. Use exrop (default of OTP 20) in most cases;
if you use exs1024 that should be changed to exs1024s;
if you stick with exsplus (default until OTP 19), use exsp instead.
If you use other algorithms, consider converting to exrop.

Also, if your code depends on the output range of
rand:uniform/1 or rand:uniform_s/1, it has been changed as follows:
OTP 18 and 19: 0.0 < X < 1.0
OTP 20: 0.0 =< X < 1.0 (note the =< operator)
where X is the output of the functions.
In short, since OTP 20, the functions may output 0.0.

I noticed the changes shortly after OTP 20.0 release.
These changes were in the last minute (19-MAR-2017 - 26-APR-2017)
just before the OTP 20 release
and after my Erlang and Elixir Factory 2017 trip so I didn't notice.
I was not notified at all by Raimo Niskanen and other contributors
about these changed either,
so I had to take time and chance to review the code again.
I know OTP is open source software and the OTP Team can modify
the code for better features and removing bugs without notifying to anyone,
so nobody is to blame on these changes.
I'm assured that Raimo and the other contributors have done a great job
on changing the details while maintaining the compatibility
and fixing the trivial bugs which I left in the code.

I would also like to note that crypto module also utilizes
the rand module API to simplify access to cryptographically strong
random number module since OTP 20. See crypto:rand_seed/{0,1}
and crypto:rand_uniform/2. This is a good example to make use of
rand module's extensible plugins.

Thanks to Tuncer Ayaz for giving me a chance to review this.

And always remember: if you are still dependent on random module,
migrate to rand module now.

Regards,
Kenji Rikitake

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
Thank you Kenji for reviewing the changes and summarizing the implications.

Sorry about not getting you into the loop during the rewrite!

As you guessed I was focused on plugging in 'crypto', fixing the flaws,
incorporating the new algorithm from Prof. Vignia and keeping it
as backwards compatible as possible, so I forgot about you...



Regarding the changed uniform float behaviour: it is the functions
rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
(OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
(OTP-20.0) documented to return 0.0 =< X < 1.0.

Previously they _could_ return exactly 0.0, even though not stated in the
documentation.  But the probability for exactly 0.0 was about 2048 times
less than it is now.  This is because the float generation has been fixed
to generate equidistant floats on the form K * 2^-53 so exactly 0.0 has now
got the same probability as all other possible float values.

I'd rather say that the documentation of rand:uniform/0 and rand:uniform_s/1
has been corrected to match their behaviour, and that the probability for
exactly 0.0 has increased from about 1/64 to about 1/53.

Despite this the distribution of generated numbers has actually not changed
- it is still uniform over the range 0.0 =< X < 1.0.

That is my view of the float changes, of which I am fairly certain. :-)


/ Raimo



On Tue, Aug 29, 2017 at 10:53:17AM +0900, Kenji Rikitake wrote:

> I finally reviewed OTP rand module change between 19.3 and 20.0.
> While most of users won't recognize the changes,
> the details are considerably different.
>
> A good news is that if you're not aware of the PRNG algorithm
> you can keep the code untouched. The new default algorithm
> works ok and even better than the OTP 19 with less bugs.
>
> On the other hand, if you explicitly specify the algorithm in rand:seed/1,
> you are suggested to use a newly-available algorithms
> described in the rand module manual of OTP 20.0. Actually
> all the old (OTP 18 and 19) algorithms are now deprecated.
> See rand module manual of OTP 20. Use exrop (default of OTP 20) in most
> cases;
> if you use exs1024 that should be changed to exs1024s;
> if you stick with exsplus (default until OTP 19), use exsp instead.
> If you use other algorithms, consider converting to exrop.
>
> Also, if your code depends on the output range of
> rand:uniform/1 or rand:uniform_s/1, it has been changed as follows:
> OTP 18 and 19: 0.0 < X < 1.0
> OTP 20: 0.0 =< X < 1.0 (note the =< operator)
> where X is the output of the functions.
> In short, since OTP 20, the functions may output 0.0.
>
> I noticed the changes shortly after OTP 20.0 release.
> These changes were in the last minute (19-MAR-2017 - 26-APR-2017)
> just before the OTP 20 release
> and after my Erlang and Elixir Factory 2017 trip so I didn't notice.
> I was not notified at all by Raimo Niskanen and other contributors
> about these changed either,
> so I had to take time and chance to review the code again.
> I know OTP is open source software and the OTP Team can modify
> the code for better features and removing bugs without notifying to anyone,
> so nobody is to blame on these changes.
> I'm assured that Raimo and the other contributors have done a great job
> on changing the details while maintaining the compatibility
> and fixing the trivial bugs which I left in the code.
>
> I would also like to note that crypto module also utilizes
> the rand module API to simplify access to cryptographically strong
> random number module since OTP 20. See crypto:rand_seed/{0,1}
> and crypto:rand_uniform/2. This is a good example to make use of
> rand module's extensible plugins.
>
> Thanks to Tuncer Ayaz for giving me a chance to review this.
>
> And always remember: if you are still dependent on random module,
> migrate to rand module now.
>
> Regards,
> Kenji Rikitake

> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions


--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Tue, Aug 29, 2017 at 10:35:28AM +0200, Raimo Niskanen wrote:

> Thank you Kenji for reviewing the changes and summarizing the implications.
>
> Sorry about not getting you into the loop during the rewrite!
>
> As you guessed I was focused on plugging in 'crypto', fixing the flaws,
> incorporating the new algorithm from Prof. Vignia and keeping it
> as backwards compatible as possible, so I forgot about you...
>
>
>
> Regarding the changed uniform float behaviour: it is the functions
> rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> (OTP-20.0) documented to return 0.0 =< X < 1.0.
>
> Previously they _could_ return exactly 0.0, even though not stated in the
> documentation.  But the probability for exactly 0.0 was about 2048 times
> less than it is now.  This is because the float generation has been fixed
> to generate equidistant floats on the form K * 2^-53 so exactly 0.0 has now
> got the same probability as all other possible float values.
>
> I'd rather say that the documentation of rand:uniform/0 and rand:uniform_s/1
> has been corrected to match their behaviour, and that the probability for
> exactly 0.0 has increased from about 1/64 to about 1/53.

Sorry!  That should be:     from about 1/2^64 to about 1/2^53.

/ Raimo


>
> Despite this the distribution of generated numbers has actually not changed
> - it is still uniform over the range 0.0 =< X < 1.0.
>
> That is my view of the float changes, of which I am fairly certain. :-)
>
>
> / Raimo
>
>
>
> On Tue, Aug 29, 2017 at 10:53:17AM +0900, Kenji Rikitake wrote:
> > I finally reviewed OTP rand module change between 19.3 and 20.0.
> > While most of users won't recognize the changes,
> > the details are considerably different.
> >
> > A good news is that if you're not aware of the PRNG algorithm
> > you can keep the code untouched. The new default algorithm
> > works ok and even better than the OTP 19 with less bugs.
> >
> > On the other hand, if you explicitly specify the algorithm in rand:seed/1,
> > you are suggested to use a newly-available algorithms
> > described in the rand module manual of OTP 20.0. Actually
> > all the old (OTP 18 and 19) algorithms are now deprecated.
> > See rand module manual of OTP 20. Use exrop (default of OTP 20) in most
> > cases;
> > if you use exs1024 that should be changed to exs1024s;
> > if you stick with exsplus (default until OTP 19), use exsp instead.
> > If you use other algorithms, consider converting to exrop.
> >
> > Also, if your code depends on the output range of
> > rand:uniform/1 or rand:uniform_s/1, it has been changed as follows:
> > OTP 18 and 19: 0.0 < X < 1.0
> > OTP 20: 0.0 =< X < 1.0 (note the =< operator)
> > where X is the output of the functions.
> > In short, since OTP 20, the functions may output 0.0.
> >
> > I noticed the changes shortly after OTP 20.0 release.
> > These changes were in the last minute (19-MAR-2017 - 26-APR-2017)
> > just before the OTP 20 release
> > and after my Erlang and Elixir Factory 2017 trip so I didn't notice.
> > I was not notified at all by Raimo Niskanen and other contributors
> > about these changed either,
> > so I had to take time and chance to review the code again.
> > I know OTP is open source software and the OTP Team can modify
> > the code for better features and removing bugs without notifying to anyone,
> > so nobody is to blame on these changes.
> > I'm assured that Raimo and the other contributors have done a great job
> > on changing the details while maintaining the compatibility
> > and fixing the trivial bugs which I left in the code.
> >
> > I would also like to note that crypto module also utilizes
> > the rand module API to simplify access to cryptographically strong
> > random number module since OTP 20. See crypto:rand_seed/{0,1}
> > and crypto:rand_uniform/2. This is a good example to make use of
> > rand module's extensible plugins.
> >
> > Thanks to Tuncer Ayaz for giving me a chance to review this.
> >
> > And always remember: if you are still dependent on random module,
> > migrate to rand module now.
> >
> > Regards,
> > Kenji Rikitake
>
> > _______________________________________________
> > erlang-questions mailing list
> > [hidden email]
> > http://erlang.org/mailman/listinfo/erlang-questions
>
>
> --
>
> / Raimo Niskanen, Erlang/OTP, Ericsson AB
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Tue, Aug 29, 2017 at 10:45:51AM +0200, Raimo Niskanen wrote:

> On Tue, Aug 29, 2017 at 10:35:28AM +0200, Raimo Niskanen wrote:
> > Thank you Kenji for reviewing the changes and summarizing the implications.
> >
> > Sorry about not getting you into the loop during the rewrite!
> >
> > As you guessed I was focused on plugging in 'crypto', fixing the flaws,
> > incorporating the new algorithm from Prof. Vignia and keeping it
> > as backwards compatible as possible, so I forgot about you...
> >
> >
> >
> > Regarding the changed uniform float behaviour: it is the functions
> > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > (OTP-20.0) documented to return 0.0 =< X < 1.0.
> >
> > Previously they _could_ return exactly 0.0, even though not stated in the
> > documentation.  But the probability for exactly 0.0 was about 2048 times
> > less than it is now.  This is because the float generation has been fixed
> > to generate equidistant floats on the form K * 2^-53 so exactly 0.0 has now
> > got the same probability as all other possible float values.
> >
> > I'd rather say that the documentation of rand:uniform/0 and rand:uniform_s/1
> > has been corrected to match their behaviour, and that the probability for
> > exactly 0.0 has increased from about 1/64 to about 1/53.
>
> Sorry!  That should be:     from about 1/2^64 to about 1/2^53.

And that was for the 64-bit generators.  For the _default_ 58-bit generator
the probability for exactly 0.0 has changed from about 1/2^58 to about
1/2^53 i.e increased with a factor 32.

/ Raimo


>
> / Raimo
>
>
> >
> > Despite this the distribution of generated numbers has actually not changed
> > - it is still uniform over the range 0.0 =< X < 1.0.
> >
> > That is my view of the float changes, of which I am fairly certain. :-)
> >
> >
> > / Raimo
> >
> >
> >
> > On Tue, Aug 29, 2017 at 10:53:17AM +0900, Kenji Rikitake wrote:
> > > I finally reviewed OTP rand module change between 19.3 and 20.0.
> > > While most of users won't recognize the changes,
> > > the details are considerably different.
> > >
> > > A good news is that if you're not aware of the PRNG algorithm
> > > you can keep the code untouched. The new default algorithm
> > > works ok and even better than the OTP 19 with less bugs.
> > >
> > > On the other hand, if you explicitly specify the algorithm in rand:seed/1,
> > > you are suggested to use a newly-available algorithms
> > > described in the rand module manual of OTP 20.0. Actually
> > > all the old (OTP 18 and 19) algorithms are now deprecated.
> > > See rand module manual of OTP 20. Use exrop (default of OTP 20) in most
> > > cases;
> > > if you use exs1024 that should be changed to exs1024s;
> > > if you stick with exsplus (default until OTP 19), use exsp instead.
> > > If you use other algorithms, consider converting to exrop.
> > >
> > > Also, if your code depends on the output range of
> > > rand:uniform/1 or rand:uniform_s/1, it has been changed as follows:
> > > OTP 18 and 19: 0.0 < X < 1.0
> > > OTP 20: 0.0 =< X < 1.0 (note the =< operator)
> > > where X is the output of the functions.
> > > In short, since OTP 20, the functions may output 0.0.
> > >
> > > I noticed the changes shortly after OTP 20.0 release.
> > > These changes were in the last minute (19-MAR-2017 - 26-APR-2017)
> > > just before the OTP 20 release
> > > and after my Erlang and Elixir Factory 2017 trip so I didn't notice.
> > > I was not notified at all by Raimo Niskanen and other contributors
> > > about these changed either,
> > > so I had to take time and chance to review the code again.
> > > I know OTP is open source software and the OTP Team can modify
> > > the code for better features and removing bugs without notifying to anyone,
> > > so nobody is to blame on these changes.
> > > I'm assured that Raimo and the other contributors have done a great job
> > > on changing the details while maintaining the compatibility
> > > and fixing the trivial bugs which I left in the code.
> > >
> > > I would also like to note that crypto module also utilizes
> > > the rand module API to simplify access to cryptographically strong
> > > random number module since OTP 20. See crypto:rand_seed/{0,1}
> > > and crypto:rand_uniform/2. This is a good example to make use of
> > > rand module's extensible plugins.
> > >
> > > Thanks to Tuncer Ayaz for giving me a chance to review this.
> > >
> > > And always remember: if you are still dependent on random module,
> > > migrate to rand module now.
> > >
> > > Regards,
> > > Kenji Rikitake
> >
> > > _______________________________________________
> > > erlang-questions mailing list
> > > [hidden email]
> > > http://erlang.org/mailman/listinfo/erlang-questions
> >
> >
> > --
> >
> > / Raimo Niskanen, Erlang/OTP, Ericsson AB
> > _______________________________________________
> > erlang-questions mailing list
> > [hidden email]
> > http://erlang.org/mailman/listinfo/erlang-questions
>
> --
>
> / Raimo Niskanen, Erlang/OTP, Ericsson AB
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Richard A. O'Keefe-2
In reply to this post by Raimo Niskanen-2


On 29/08/17 8:35 PM, Raimo Niskanen wrote:
>
> Regarding the changed uniform float behaviour: it is the functions
> rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> (OTP-20.0) documented to return 0.0 =< X < 1.0.

There are applications of random numbers for which it is important
that 0 never be returned.  Of course, nothing stops me writing

uniform_nonzero() ->
     X = rand:uniform(),
     if X >  0.0 -> X
      ; X =< 0.0 -> uniform_nonzero()
     end.

but it would be nice to have this already in the library.

(I know the old library had the same gap.  But with such a major
reworking of random number generation, it's time to close it.)

_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:

>
>
> On 29/08/17 8:35 PM, Raimo Niskanen wrote:
> >
> > Regarding the changed uniform float behaviour: it is the functions
> > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > (OTP-20.0) documented to return 0.0 =< X < 1.0.
>
> There are applications of random numbers for which it is important
> that 0 never be returned.  Of course, nothing stops me writing

What kind of applications?  I would like to get a grip on how needed this
function is?

>
> uniform_nonzero() ->
>      X = rand:uniform(),
>      if X >  0.0 -> X
>       ; X =< 0.0 -> uniform_nonzero()
>      end.
>
> but it would be nice to have this already in the library.
>
> (I know the old library had the same gap.  But with such a major
> reworking of random number generation, it's time to close it.)

We chose 0.0 =< X < 1.0 because it was most like the integer generator i.e
including the lower bound but excluding the upper.  And as you say it is
easy to exclude the lower bound.

If we would implement 0.0 < X < 1.0, would then 0.0 =< X =< 1.0 also be
missing, and for completeness 0.0 < X =< 1.0?
Which of the four are worth implementing?

You clould argue that including both bounds is the most general
because it is easy to retry if you want to exclude a value.

Maybe something like:
    uniform(Opts) -> float()
    uniform_s(Opts, State) -> float()
        Opts :: [(exclude_zero | exclude_one)]


>
> _______________________________________________
> erlang-questions mailing list
> [hidden email]
> http://erlang.org/mailman/listinfo/erlang-questions

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

zxq9-2
On 2017年08月30日 水曜日 08:42:02 Raimo Niskanen wrote:

> On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:
> >
> >
> > On 29/08/17 8:35 PM, Raimo Niskanen wrote:
> > >
> > > Regarding the changed uniform float behaviour: it is the functions
> > > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > > (OTP-20.0) documented to return 0.0 =< X < 1.0.
> >
> > There are applications of random numbers for which it is important
> > that 0 never be returned.  Of course, nothing stops me writing
>
> What kind of applications?  I would like to get a grip on how needed this
> function is?

Any function where a zero would propagate.

This can be exactly as bad as accidentally comparing a NULL in SQL.

-Craig
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Wed, Aug 30, 2017 at 03:48:16PM +0900, zxq9 wrote:

> On 2017年08月30日 水曜日 08:42:02 Raimo Niskanen wrote:
> > On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:
> > >
> > >
> > > On 29/08/17 8:35 PM, Raimo Niskanen wrote:
> > > >
> > > > Regarding the changed uniform float behaviour: it is the functions
> > > > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > > > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > > > (OTP-20.0) documented to return 0.0 =< X < 1.0.
> > >
> > > There are applications of random numbers for which it is important
> > > that 0 never be returned.  Of course, nothing stops me writing
> >
> > What kind of applications?  I would like to get a grip on how needed this
> > function is?
>
> Any function where a zero would propagate.
>
> This can be exactly as bad as accidentally comparing a NULL in SQL.

That's vague for me.

Are you saying it is a common enought use pattern to divide with a
random number?  Are there other reasons when a float() =:= 0.0 is fatal?


>
> -Craig

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

zxq9-2
On 2017年08月30日 水曜日 08:54:30 Raimo Niskanen wrote:

> On Wed, Aug 30, 2017 at 03:48:16PM +0900, zxq9 wrote:
> > On 2017年08月30日 水曜日 08:42:02 Raimo Niskanen wrote:
> > > On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:
> > > >
> > > >
> > > > On 29/08/17 8:35 PM, Raimo Niskanen wrote:
> > > > >
> > > > > Regarding the changed uniform float behaviour: it is the functions
> > > > > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > > > > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > > > > (OTP-20.0) documented to return 0.0 =< X < 1.0.
> > > >
> > > > There are applications of random numbers for which it is important
> > > > that 0 never be returned.  Of course, nothing stops me writing
> > >
> > > What kind of applications?  I would like to get a grip on how needed this
> > > function is?
> >
> > Any function where a zero would propagate.
> >
> > This can be exactly as bad as accidentally comparing a NULL in SQL.
>
> That's vague for me.
>
> Are you saying it is a common enought use pattern to divide with a
> random number?  Are there other reasons when a float() =:= 0.0 is fatal?

It is relatively common whenever it is guaranteed to be safe! Otherwise it becomes a guarded expression.

Sure, that is a case of "well, just write it so that it can't do that" -- but the original function spec told us we didn't need to do that, so there is code out there that would rely on not using a factor of 0.0. I've probably written some in game servers, actually.

Propagating the product of multiplication by 0.0 is the more common problem I've seen, by the way, as opposed to division.

Consider: character stat generation in games, offset-by-random-factor calculations where accidentally getting exactly the same result is catastrophic, anti-precision routines in some aiming devices and simulations, adding wiggle to character pathfinding, unstuck() type routines, mutating a value in evolutionary design algorithms, and so on.

Very few of these cases are catastrophic and many would simply be applied again if the initial attempt failed, but a few can be very bad depending on how the system in which they are used is designed. The problem isn't so much that "there aren't many use cases" or "the uses aren't common" as much as the API was originally documented that way, and it has changed for no apparent reason. Zero has a very special place in mathematics and should be treated carefully.

I think ROK would have objected a lot less had the original spec been 0.0 =< X =< 1.0 (which is different from being 0.0 =< X < 1.0; which is another point of potentially dangerous weirdness). I'm curious to see what examples he comes up with. The ones above are just off the top of my head, and like I mentioned most of my personal examples don't happen to be really catastrophic in most cases because many of them involve offsetting from a known value (which would be relatively safe to reuse) or situations where failures are implicitly assumed to provoke retries.

-Craig
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Wed, Aug 30, 2017 at 04:14:56PM +0900, zxq9 wrote:

> On 2017年08月30日 水曜日 08:54:30 Raimo Niskanen wrote:
> > On Wed, Aug 30, 2017 at 03:48:16PM +0900, zxq9 wrote:
> > > On 2017年08月30日 水曜日 08:42:02 Raimo Niskanen wrote:
> > > > On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:
> > > > >
> > > > >
> > > > > On 29/08/17 8:35 PM, Raimo Niskanen wrote:
> > > > > >
> > > > > > Regarding the changed uniform float behaviour: it is the functions
> > > > > > rand:uniform/0 and rand:uniform_s/1 this concerns.  They were previously
> > > > > > (OTP-19.3) documented to output a value 0.0 < X < 1.0 and are now
> > > > > > (OTP-20.0) documented to return 0.0 =< X < 1.0.
> > > > >
> > > > > There are applications of random numbers for which it is important
> > > > > that 0 never be returned.  Of course, nothing stops me writing
> > > >
> > > > What kind of applications?  I would like to get a grip on how needed this
> > > > function is?
> > >
> > > Any function where a zero would propagate.
> > >
> > > This can be exactly as bad as accidentally comparing a NULL in SQL.
> >
> > That's vague for me.
> >
> > Are you saying it is a common enought use pattern to divide with a
> > random number?  Are there other reasons when a float() =:= 0.0 is fatal?
>
> It is relatively common whenever it is guaranteed to be safe! Otherwise it becomes a guarded expression.
>
> Sure, that is a case of "well, just write it so that it can't do that" -- but the original function spec told us we didn't need to do that, so there is code out there that would rely on not using a factor of 0.0. I've probably written some in game servers, actually.
>
> Propagating the product of multiplication by 0.0 is the more common problem I've seen, by the way, as opposed to division.
>
> Consider: character stat generation in games, offset-by-random-factor calculations where accidentally getting exactly the same result is catastrophic, anti-precision routines in some aiming devices and simulations, adding wiggle to character pathfinding, unstuck() type routines, mutating a value in evolutionary design algorithms, and so on.
>
> Very few of these cases are catastrophic and many would simply be applied again if the initial attempt failed, but a few can be very bad depending on how the system in which they are used is designed. The problem isn't so much that "there aren't many use cases" or "the uses aren't common" as much as the API was originally documented that way, and it has changed for no apparent reason. Zero has a very special place in mathematics and should be treated carefully.

The spec did not match the reality.  Either had to be corrected.
It is in general safer to change the documentation to match the reality.

So I do not agree that the spec changed for no apparent reason.

Furthermore Java's Random:nextFloat(), Python's random.random() and
Ruby's Random.rand all generate in the same interval:
    http://docs.oracle.com/javase/6/docs/api/java/util/Random.html#nextFloat()
    https://docs.python.org/3/library/random.html#random.random
    http://ruby-doc.org/core-2.0.0/Random.html#method-i-rand

I think this all boils down to the fact that digital floating point values
(IEEE 754) has limited precision and in the interval 0.0 to 1.0 are better
regarded as 53 bit fixed point values.

A half open interval matches integer random number generators that also
in general use half open intervals.

With half open intervals you can generate numbers in [0.0,1.0) and other
numbers in [1.0,2.0), where the number 1.0 belongs to only one of these intervals.

This I think is a good default behaviour.


>
> I think ROK would have objected a lot less had the original spec been 0.0 =< X =< 1.0 (which is different from being 0.0 =< X < 1.0; which is another point of potentially dangerous weirdness). I'm curious to see what examples he comes up with. The ones above are just off the top of my head, and like I mentioned most of my personal examples don't happen to be really catastrophic in most cases because many of them involve offsetting from a known value (which would be relatively safe to reuse) or situations where failures are implicitly assumed to provoke retries.
>
> -Craig

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

zxq9-2
On 2017年08月30日 水曜日 10:29:12 Raimo Niskanen wrote:

> It is in general safer to change the documentation to match the reality.

Wow.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Richard A. O'Keefe-2
In reply to this post by Raimo Niskanen-2


On 30/08/17 6:42 PM, Raimo Niskanen wrote:
> On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:

>> There are applications of random numbers for which it is important
>> that 0 never be returned.  Of course, nothing stops me writing
>
> What kind of applications?  I would like to get a grip on how needed this
> function is?

I'll give you just one example.  There are two ways I know to generate
normally distributed random numbers.  One of them goes like this:

     sqrt(-2 * ln(randnz()) * cos(pi * random())

where random() is in [0,1) but randnz() must be in (0,1).

OK, I'll give you another example.  This is part of an algorithm for
generating gamma variates, one of the best known.

     U <- random()
     if U <= r then
         z <- -ln(U/r)
     else
         z <- ln(random()/lambda)
     end

You will notice that both of the calls to ln will go wrong if
random() can return 0.

These aren't the only examples, but I have an appointment.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Raimo Niskanen-2
On Thu, Aug 31, 2017 at 10:34:16AM +1200, Richard A. O'Keefe wrote:

>
>
> On 30/08/17 6:42 PM, Raimo Niskanen wrote:
> > On Wed, Aug 30, 2017 at 11:44:57AM +1200, Richard A. O'Keefe wrote:
>
> >> There are applications of random numbers for which it is important
> >> that 0 never be returned.  Of course, nothing stops me writing
> >
> > What kind of applications?  I would like to get a grip on how needed this
> > function is?
>
> I'll give you just one example.  There are two ways I know to generate
> normally distributed random numbers.  One of them goes like this:
>
>      sqrt(-2 * ln(randnz()) * cos(pi * random())
>
> where random() is in [0,1) but randnz() must be in (0,1).
>
> OK, I'll give you another example.  This is part of an algorithm for
> generating gamma variates, one of the best known.
>
>      U <- random()
>      if U <= r then
>          z <- -ln(U/r)
>      else
>          z <- ln(random()/lambda)
>      end
>
> You will notice that both of the calls to ln will go wrong if
> random() can return 0.
>
> These aren't the only examples, but I have an appointment.

Thank you!

Should I make a pull request of this?

    https://github.com/erlang/otp/compare/OTP-20.0...RaimoNiskanen:raimo/stdlib/rand-uniformNZ

Is the name uniformNZ good enough?
Are uniform floats complete enough with this addition?

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Loïc Hoguin-3
In reply to this post by zxq9-2
On 08/30/2017 12:33 PM, zxq9 wrote:
> On 2017年08月30日 水曜日 10:29:12 Raimo Niskanen wrote:
>
>> It is in general safer to change the documentation to match the reality.
>
> Wow.

I certainly hope this is not the general policy for OTP. We program
against the documentation. The documentation *is* our reality.

It also seems it's not even listed in the release notes. We program
against the documentation, if the documentation has a breaking changes
it would be great to know about it.

--
Loïc Hoguin
https://ninenines.eu
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Jesper Louis Andersen-2
On Thu, Aug 31, 2017 at 3:42 PM Loïc Hoguin <[hidden email]> wrote:

I certainly hope this is not the general policy for OTP. We program
against the documentation. The documentation *is* our reality.


I think it is fair to evaluate on a case by case basis. Some times, the documentation and the implementation are not matching up. This means either the documentation or the implementation is wrong (not xor here!). Which of which is wrong depends a bit on the case, and there are definitely borderline situations where it is very hard to determine which way you should let the thing fall.

I don't think you can make blanket statements on which way you should lean because there are good counterexamples in both "camps" so to speak.

Another view is that the documentation is the specification. But again, both the specification and the implementation can be wrong and some times the correct operation is to change the specification. When I worked with formal semantics, it was quite common that you altered the specification in ways that let you prove a meta-theoretic property about the specification. Not altering it would simply make the proof way to complicated and hard. Perhaps even impossible. It is an extreme variant of letting the documentation match the reality in a certain sense.


_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Loïc Hoguin-3
On 08/31/2017 04:20 PM, Jesper Louis Andersen wrote:
> On Thu, Aug 31, 2017 at 3:42 PM Loïc Hoguin <[hidden email]
> <mailto:[hidden email]>> wrote:
>
>
>     I certainly hope this is not the general policy for OTP. We program
>     against the documentation. The documentation *is* our reality.
>
>
> I think it is fair to evaluate on a case by case basis.

I'm not arguing against that, but rather against that it's "in general
safer to change the documentation".

It should be a case by case basis but it's also important to recognize
that users write software against the documentation, and to take this
into account when making breaking changes.

To give an example, if such a thing were to happen in Cowboy, which
follows semver, two cases could happen:

* The documentation is wrong but the next version is a patch release:
fix the code to match the documentation. The rule is: don't break
people's programs.

* The documentation is wrong but the next version is a major release:
fix the documentation AND announce it as a breaking change (with all
details; and probably release a patch release for the old version as
above). The rule is: breaking people's programs is OK, just make sure
you tell them about it!

> I don't think you can make blanket statements on which way you should
> lean because there are good counterexamples in both "camps" so to speak.

Properly matching people's expectations is a lot more important than
whatever counterexamples may exist.

--
Loïc Hoguin
https://ninenines.eu
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Attila Rajmund Nohl
In reply to this post by Loïc Hoguin-3
2017-08-31 15:42 GMT+02:00 Loïc Hoguin <[hidden email]>:

> On 08/30/2017 12:33 PM, zxq9 wrote:
>>
>> On 2017年08月30日 水曜日 10:29:12 Raimo Niskanen wrote:
>>
>>> It is in general safer to change the documentation to match the reality.
>>
>>
>> Wow.
>
>
> I certainly hope this is not the general policy for OTP. We program against
> the documentation. The documentation *is* our reality.

I disagree. Take this example:
https://lwn.net/SubscriberLink/732420/9b9f8f2825f1877f/ The printk()
function in the Linux kernel was documented to print new logs to new
lines unless the KERN_CONT option was passed. In reality it didn't
always started new lines and people expected (maybe even relied on)
this - and when the code was updated to match the documentation, they
were genuinely surprised when their code was broken.
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

zxq9-2
In reply to this post by Jesper Louis Andersen-2
On 2017年08月31日 木曜日 14:20:55 Jesper Louis Andersen wrote:

> On Thu, Aug 31, 2017 at 3:42 PM Loïc Hoguin <[hidden email]> wrote:
>
> >
> > I certainly hope this is not the general policy for OTP. We program
> > against the documentation. The documentation *is* our reality.
> >
> >
> I think it is fair to evaluate on a case by case basis. Some times, the
> documentation and the implementation are not matching up. This means either
> the documentation or the implementation is wrong (not xor here!). Which of
> which is wrong depends a bit on the case, and there are definitely
> borderline situations where it is very hard to determine which way you
> should let the thing fall.
>
> I don't think you can make blanket statements on which way you should lean
> because there are good counterexamples in both "camps" so to speak.
>
> Another view is that the documentation is the specification. But again,
> both the specification and the implementation can be wrong and some times
> the correct operation is to change the specification. When I worked with
> formal semantics, it was quite common that you altered the specification in
> ways that let you prove a meta-theoretic property about the specification.
> Not altering it would simply make the proof way to complicated and hard.
> Perhaps even impossible. It is an extreme variant of letting the
> documentation match the reality in a certain sense.

The other route is to make existing functions do what they say they are going to whenever possible, add functions that provide the prescribed functionality, and deprecate and annotate (with warnings where appropriate) the ones that cannot provide whatever they originally claimed to. And be quite noisy about all of this.

OTP has many, many examples of this. It prevents surprise breakage of old code that depends on some particular (and occasionally peculiar) behavior while forging a path ahead -- allowing users to make an informed decision to review and update old code or stick with an older version of the runtime (which tends to be the more costly choice in many cases, but at least it can be an informed decision).

Consider what happened with now/0, for example. Now we have a more complex family of time functions but never was it viewed as an acceptable approach to simply shift documentation around a bit here and there in a rather quiet manner while adding in contextual execution features (that is to say, hidden states) that would cause now/0 to behave in a new way. And now/0 is deprecated.

> I think it is fair to evaluate on a case by case basis.

OK. I'll buy that.

In an EXTREMELY limited number of cases you will have a function that simply cannot live up to its spec without a ridiculous amount of nitpicky work that wouldn't really matter to anyone. This is not one of those cases. And in this case we are talking about providing a largely pure API in the standard library, not some meta behavior that acts indirectly through a rewrite system based on some proofing mechanics where the effects of improper definitions are magnified with each transformation.

So I get what you're saying, but this is not one of those cases, and for those odd cases it is much safer to deprecate functions, mark them as unsafe, provide compiler warnings and so on if the situation is just THAT BAD, and write a new function that is properly documented in a way that won't suddenly change later. For a functional language's standard library the majority of functions aren't going to be magically tricky, and specs are concrete promises while implementations ephemeral.

At least this change happened in a major release, not a minor one. If it is forgivable anywhere, it is in a major release. The tricky bit is that the promises a language's standard libs make to authors are a bit more sticky than those made by separate libraries provided in a given language. And yes, that is at least as much part of the social contract inherent in the human part of the programming world as it is a part of the technical contract implicit in published documentation. The social part of the contract is more important, from what I've seen. Consider why Ruby and many previously popular JS frameworks are considered to be cancer now -- its not just because things changed, it is that the way they changed jerked people around.

The issue I am addressing is a LOT more important than whether `0 =< X < 1.0`, of course (yeah, on this one issue, we'll figure it out). It is a general attitude that is absolutely dangerous.

>> It is in general safer to change the documentation to match the reality.

This is as corrosive a statement as can be. We need to think very carefully about that before this sort of thinking starts becoming common in other areas of OTP in general.

-Craig
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

Loïc Hoguin-3
In reply to this post by Attila Rajmund Nohl
On 08/31/2017 05:13 PM, Attila Rajmund Nohl wrote:

> 2017-08-31 15:42 GMT+02:00 Loïc Hoguin <[hidden email]>:
>> On 08/30/2017 12:33 PM, zxq9 wrote:
>>>
>>> On 2017年08月30日 水曜日 10:29:12 Raimo Niskanen wrote:
>>>
>>>> It is in general safer to change the documentation to match the reality.
>>>
>>>
>>> Wow.
>>
>>
>> I certainly hope this is not the general policy for OTP. We program against
>> the documentation. The documentation *is* our reality.
>
> I disagree. Take this example:
> https://lwn.net/SubscriberLink/732420/9b9f8f2825f1877f/ The printk()
> function in the Linux kernel was documented to print new logs to new
> lines unless the KERN_CONT option was passed. In reality it didn't
> always started new lines and people expected (maybe even relied on)
> this - and when the code was updated to match the documentation, they
> were genuinely surprised when their code was broken.

This story is not about people following the documentation and then have
the documentation be "fixed" under their feet without them noticing, it
is in fact the complete opposite.

--
Loïc Hoguin
https://ninenines.eu
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
Reply | Threaded
Open this post in threaded view
|

Re: On OTP rand module difference between OTP 19 and OTP 20

zxq9-2
In reply to this post by zxq9-2
On 2017年09月01日 金曜日 00:19:26 zxq9 wrote:
> `0 =< X < 1.0`

DHOH! Yes, I know, I know...

 0.0 =< X < 1.0

 /(>.<)\
_______________________________________________
erlang-questions mailing list
[hidden email]
http://erlang.org/mailman/listinfo/erlang-questions
123