Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Ruby (http://www.velocityreviews.com/forums/f66-ruby.html)
-   -   rand(-10..10) (http://www.velocityreviews.com/forums/t831774-rand-10-10-a.html)

 Schüle Daniel 07-27-2006 12:39 AM

rand(-10..10)

Hi all,

wouldn't it make sense to allow

rand -10..10

be aquivalent to

-10 + rand(20)

the first is by far more obvious.
Of course rand -10...10 should work too.
What do you think?

--
Daniel

 Schüle Daniel 07-27-2006 12:49 AM

Re: rand(-10..10)

one solution could be

irb(main):210:0* class Range
irb(main):211:1> def rand
irb(main):212:2> return self.begin + Kernel.rand(self.end-self.begin)
irb(main):213:2> end
irb(main):214:1> end
=> nil
irb(main):215:0> (-10..10).rand
=> 2
irb(main):216:0> (-10..10).rand
=> 6
irb(main):217:0> (-10..10).rand
=> 4
irb(main):218:0> (-10..10).rand
=> -1

it's a matter of style to write

rand(-10..10) or (-10..10).rand

but since 10.sin doesn't work, as opposite tosin(10)
non object oriented rand(-10..10) is also a nice thing to have.

 Morton Goldberg 07-27-2006 05:02 AM

Re: rand(-10..10)

I had similar thoughts a while back. I decided that extending Kernel =20
and mimicing the behavior of rand was the way to go. My code follows:

Regards, Morton

------ code starts
#!/usr/bin/ruby

# Extend Kernel with an enhanced uniform random number generator.
# Has the same behavior as rand for a single argument.
module Kernel
URAND_ARG_ERR =3D "Arguments not valid for urand"
# Return a pseudo-random number in the range 0.0...1.0, 0...m, or =20=

m..n.
def urand(m=3D0, n=3Dnil)
case m
when Range
m, n =3D m.begin, m.end
when Integer
return rand(m) if n.nil?
else
raise ArgumentError, URAND_ARG_ERR
end
raise ArgumentError, URAND_ARG_ERR if n < m
m + rand(n - m + 1)
end
end

# Now for a little testing ...
def test(times, m=3D0, n=3Dnil)
r =3D Array.new(times)
if n.nil? then
if m =3D=3D 0 then r.collect! {urand}
else r.collect! {urand(m)}
end
else r.collect! {urand(m, n)}
end
p r
end
test(3) # =3D> [0.0403243284672499, 0.875487065408379, =20
0.142408860381693]
test(3, 11, 11) # =3D> [11, 11, 11]
test(10, 3) # =3D> [0, 1, 2, 0, 1, 0, 1, 2, 0, 0]
test(10, -1..1) # =3D> [0, 0, 1, -1, -1, 1, -1, 1, -1, 0]
test(10, 100, 200) # =3D> [126, 148, 183, 140, 188, 175, 115, 157, 136, =20=

179]
begin
test(1, 3, -1)
rescue ArgumentError =3D> error
puts error.message
end # =3D> Arguments not valid for urand

------ code ends

On Jul 26, 2006, at 8:50 PM, Sch=FCle Daniel wrote:

> one solution could be
>
> irb(main):210:0* class Range
> irb(main):211:1> def rand
> irb(main):212:2> return self.begin + Kernel.rand(self.end-self.begin)
> irb(main):213:2> end
> irb(main):214:1> end
> =3D> nil
> irb(main):215:0> (-10..10).rand
> =3D> 2
> irb(main):216:0> (-10..10).rand
> =3D> 6
> irb(main):217:0> (-10..10).rand
> =3D> 4
> irb(main):218:0> (-10..10).rand
> =3D> -1
>
> it's a matter of style to write
>
> rand(-10..10) or (-10..10).rand
>
> but since 10.sin doesn't work, as opposite tosin(10)
> non object oriented rand(-10..10) is also a nice thing to have.

 Dr Nic 07-27-2006 01:53 PM

Re: rand(-10..10)

> irb(main):215:0> (-10..10).rand
> => 2
> irb(main):216:0> (-10..10).rand
> => 6
> irb(main):217:0> (-10..10).rand
> => 4
> irb(main):218:0> (-10..10).rand
> => -1

*Sniff* God I love Ruby.

--
Posted via http://www.ruby-forum.com/.

 Marc Heiler 07-27-2006 02:07 PM

Re: rand(-10..10)

"the first is by far more obvious."

I think it looks ugly. :-)

(-10..10).rand
looks much nicer IMHO.

--
Posted via http://www.ruby-forum.com/.

 Daniel Schierbeck 07-27-2006 03:21 PM

Re: rand(-10..10)

Marc Heiler wrote:
> "the first is by far more obvious."
>
> I think it looks ugly. :-)
>
> (-10..10).rand
> looks much nicer IMHO.

This should work with all enumerables:

module Enumerable
def rand
entries = entries
entries.at(Kernel.rand(entries.length))
end
end

I can't seem to get around the `entries = entries' part -- I don't want
to convert the enumerable to an array more than once. Any ideas?

Cheers,
Daniel

 ChrisH 07-27-2006 04:20 PM

Re: rand(-10..10)

Daniel Schierbeck wrote:
....
> This should work with all enumerables:
>
> module Enumerable
> def rand
> entries = entries
> entries.at(Kernel.rand(entries.length))
> end
> end
>
> I can't seem to get around the `entries = entries' part -- I don't want
> to convert the enumerable to an array more than once. Any ideas?

Enumerable supports sort_by, so could just use:

module Enumerable
def rand
self.sort_by{Kernel.rand}.last
end
end

Cheers
Chris

 Daniel Schierbeck 07-27-2006 05:42 PM

Re: rand(-10..10)

ChrisH wrote:
> Daniel Schierbeck wrote:
> ...
>> This should work with all enumerables:
>>
>> module Enumerable
>> def rand
>> entries = entries
>> entries.at(Kernel.rand(entries.length))
>> end
>> end
>>
>> I can't seem to get around the `entries = entries' part -- I don't want
>> to convert the enumerable to an array more than once. Any ideas?

>
> Enumerable supports sort_by, so could just use:
>
> module Enumerable
> def rand
> self.sort_by{Kernel.rand}.last
> end
> end

I think sorting the entire enumerable may be slight overkill, although
it of course is prettier :)

Daniel

 Daniel Martin 07-27-2006 06:45 PM

Re: rand(-10..10)

Daniel Schierbeck <daniel.schierbeck@gmail.com> writes:

>>> This should work with all enumerables:
>>>
>>> module Enumerable
>>> def rand
>>> entries = entries
>>> entries.at(Kernel.rand(entries.length))
>>> end
>>> end
>>>
>>> I can't seem to get around the `entries = entries' part -- I don't want
>>> to convert the enumerable to an array more than once. Any ideas?

There's also this, which is possibly more memory-efficient (if the
Enumerable in question chews large amounts of memory when being
converted to an array, but not with each), but is almost certainly
much slower, since it calls rand once per element:

module Enumerable
def rand
ret, i = nil, 0
each {|v| ret = v if 0 == Kernel.rand(i += 1)}
ret
end
end

Test code for irb:

h=Hash.new(0); 10000.times {h[%w{a b c d e}.rand] += 1}; h

 Florian Frank 07-27-2006 07:26 PM

Re: rand(-10..10)

Daniel Martin wrote:
> module Enumerable
> def rand
> ret, i = nil, 0
> each {|v| ret = v if 0 == Kernel.rand(i += 1)}
> ret
> end
> end
>
> Test code for irb:
>
> h=Hash.new(0); 10000.times {h[%w{a b c d e}.rand] += 1}; h
>

I think you shouldn't name this method rand. It shadows Kernel.rand in
all classes, that already call rand and include Enumerable. The same is
true for Range#rand, if people inherit from Range and already call rand.
Ruby makes those things possible, but it's also very easy to shoot
yourself or others into the foot, if you aren't careful.

The Kernel#rand(-5..15) version wouldn't suffer from this problem. It
would be a good idea to add this to ruby core, because this
functionality is something, that is needed very often.

--
Florian Frank

All times are GMT. The time now is 06:37 AM.