Forum: Ruby Random#rand_inclusive?

Posted by Robert Feldt (Guest)
on 2013-03-07 08:56
(Received via mailing list)
Hi,

Random#rand and Kernel#rand are exclusive i.e. they return a value >= 
0.0
but <max if max is a Float. What if one wants a rand that is inclusive 
of
the max? Would any of the below approaches guarantee to give an 
inclusive
range?

class Random
  # Return a random number between 0 (inclusive) and max (inclusive).
  def rand_incl(max = 1.0)
    if Float === max
      rand(max+Float::EPSILON)
    elsif Integer === max
      rand(max+1)
    end
  end

  # Same but with other strategy
  def rand_incl2(max = 1.0)
    if Float === max
      num_floats = (max - min)/Float::EPSILON
      min + rand(1+num_floats.to_i) * Float::EPSILON
    elsif Integer === max
      min + rand(max+1-min)
    end
  end
end

Thanks in advance,

Robert Feldt
Posted by Matthew Kerwin (mattyk)
on 2013-03-07 09:30
(Received via mailing list)
OTOH, without looking up exactly what Epsilon is (the smallest possible
absolute interval represented by a float?), wouldn't your technique fail 
if
max is big, because {big float} + {small float} = {big float} ?  I'd
suggest something clever with Rationals, personally, along the lines of
`(max*rand(range+1))/range"

Sent from my phone, so excuse the typos.
Posted by Robert Klemme (robert_k78)
on 2013-03-07 10:31
(Received via mailing list)
On Thu, Mar 7, 2013 at 8:55 AM, Robert Feldt <robert.feldt@gmail.com> 
wrote:

> Random#rand and Kernel#rand are exclusive i.e. they return a value >= 0.0
> but <max if max is a Float. What if one wants a rand that is inclusive of
> the max? Would any of the below approaches guarantee to give an inclusive
> range?

I don't think there is any good way to achieve that for floats.  You
could try rounding but this would effectively mean to reduce the
number of significant decimals.

def rand_incl(float, decimals = 10)
  rand(float).round(decimals)
end

I would have to reason a bit longer about what that does to
statistical distribution of values.  It might still not be exactly
evenly distributed - especially since the edge values have fewer
values to round to (i.e. negatives are missing and values >= max).
Nah, forget it: does not look like a good idea.

Kind regards

robert
Posted by Matthew Kerwin (mattyk)
on 2013-03-07 12:22
(Received via mailing list)
On 7 March 2013 17:55, Robert Feldt <robert.feldt@gmail.com> wrote:

>
> Random#rand and Kernel#rand are exclusive i.e. they return a value >= 0.0
> but <max if max is a Float. What if one wants a rand that is inclusive of
> the max?
>

I'm back at a computer now, and have looked up the docs for Random#rand.
Apparently in 2.0 you can simply pass an inclusive range and it will do
what you want, e.g.:  Random.rand(0.0..max)  <
http://ruby-doc.org/core-2.0/Random.html#method-i-rand>

However in 1.9, yeah, your rand_incl2 is basically what I'd do.  I
independently came up with a simplified version:
https://gist.github.com/phluid61/5107356
Posted by Robert Feldt (Guest)
on 2013-03-07 13:02
(Received via mailing list)
Thanks Matthew, didn't know that about 2.0.

Cheers,

Robert

On Thu, Mar 7, 2013 at 12:21 PM, Matthew Kerwin 
<matthew@kerwin.net.au>wrote:

> what you want, e.g.:  Random.rand(0.0..max)  <
> http://ruby-doc.org/core-2.0/Random.html#method-i-rand>
>
> However in 1.9, yeah, your rand_incl2 is basically what I'd do.  I
> independently came up with a simplified version:
> https://gist.github.com/phluid61/5107356
>



--
Best regards,

/Robert Feldt
--
Tech. Dr. (PhD), Assoc. Professor in Software Engineering
Chalmers, Software Engineering Dept
Blekinge Institute of Technology, Software Engineering Research Lab
robert.feldt (a) chalmers.se     or     robert.feldt (a) gmail.com
Mobile phone: +46 (0) 733 580 580
http://www.cse.chalmers.se/~feldt
Please log in before posting. Registration is free and takes only a minute.
Existing account (Switch to SSL-encrypted connection)
NEW: Do you have a Google/GoogleMail or Yahoo account? No registration required!
Log in with Google account | Log in with Yahoo account
No account? Register here.