Reputation: 764
Say you want to generate a random number between 1 and 1 billion:
rand(1..1_000_000_000)
Will Ruby create an array from that range every time you call this line of code?
Rubocop suggests this approach over rand(1_000_000_000)+1
but it seems there's potential for pain.
Ruby's docs say this:
# When +max+ is a Range, +rand+ returns a random number where
# range.member?(number) == true.
Where +max+
is the argument passed to rand
, but it doesn't say how it gets the number
argument. I'm also not sure if calling .member?
on a range is performant.
Any ideas?
I can use benchmark but still curious about the inner workings here.
Upvotes: 2
Views: 737
Reputation: 4893
No, Ruby will not create an array from that range, unless you explicitly call the .to_a
method on the Range
object. In fact, rand()
doesn't work on arrays - .sample
is the method to use for returning a random element from an array.
The Range
class includes Enumerable
so you get Enumerable's iteration methods without having to convert the range into an array. The lower and upper limits for a Range are (-Float::INFINITY..Float::INFINITY)
, although that will result in a Numerical argument out of domain
error if you pass it into rand
.
As for .member?
, that method simply calls a C function called range_cover
that calls another one called r_cover_p
which checks if a value is between two numbers or strings.
To test the difference in speed between passing a range to rand
and calling sample
on an array, you can perform the following test:
require 'benchmark'
puts Benchmark.measure { rand(0..10_000_000) }
=> 0.000000 0.000000 0.000000 ( 0.000009)
puts Benchmark.measure { (0..10_000_000).to_a.sample }
=> 0.300000 0.030000 0.330000 ( 0.347752)
As you can see in the first example, passing in a range
as a parameter to rand
is extremely rapid.
Contrarily, calling .to_a.sample
on a range is rather slow. This is due to the array creation process which requires allocating the appropriate data into memory. The .sample
method should be relatively fast as it simply passes a random and unique index into the array and returns that element.
To check out the code for range
have a look here.
Upvotes: 4