How to get a random number in Ruby

546,169

Solution 1

Use rand(range)

From Ruby Random Numbers:

If you needed a random integer to simulate a roll of a six-sided die, you'd use: 1 + rand(6). A roll in craps could be simulated with 2 + rand(6) + rand(6).

Finally, if you just need a random float, just call rand with no arguments.


As Marc-André Lafortune mentions in his answer below (go upvote it), Ruby 1.9.2 has its own Random class (that Marc-André himself helped to debug, hence the 1.9.2 target for that feature).

For instance, in this game where you need to guess 10 numbers, you can initialize them with:

10.times.map{ 20 + Random.rand(11) } 
#=> [26, 26, 22, 20, 30, 26, 23, 23, 25, 22]

Note:

This is why the equivalent of Random.new.rand(20..30) would be 20 + Random.rand(11), since Random.rand(int) returns “a random integer greater than or equal to zero and less than the argument.” 20..30 includes 30, I need to come up with a random number between 0 and 11, excluding 11.

Solution 2

While you can use rand(42-10) + 10 to get a random number between 10 and 42 (where 10 is inclusive and 42 exclusive), there's a better way since Ruby 1.9.3, where you are able to call:

rand(10...42) # => 13

Available for all versions of Ruby by requiring my backports gem.

Ruby 1.9.2 also introduced the Random class so you can create your own random number generator objects and has a nice API:

r = Random.new
r.rand(10...42) # => 22
r.bytes(3) # => "rnd"

The Random class itself acts as a random generator, so you call directly:

Random.rand(10...42) # => same as rand(10...42)

Notes on Random.new

In most cases, the simplest is to use rand or Random.rand. Creating a new random generator each time you want a random number is a really bad idea. If you do this, you will get the random properties of the initial seeding algorithm which are atrocious compared to the properties of the random generator itself.

If you use Random.new, you should thus call it as rarely as possible, for example once as MyApp::Random = Random.new and use it everywhere else.

The cases where Random.new is helpful are the following:

  • you are writing a gem and don't want to interfere with the sequence of rand/Random.rand that the main programs might be relying on
  • you want separate reproducible sequences of random numbers (say one per thread)
  • you want to be able to save and resume a reproducible sequence of random numbers (easy as Random objects can marshalled)

Solution 3

If you're not only seeking for a number but also hex or uuid it's worth mentioning that the SecureRandom module found its way from ActiveSupport to the ruby core in 1.9.2+. So without the need for a full blown framework:

require 'securerandom'

p SecureRandom.random_number(100) #=> 15
p SecureRandom.random_number(100) #=> 88

p SecureRandom.random_number #=> 0.596506046187744
p SecureRandom.random_number #=> 0.350621695741409

p SecureRandom.hex #=> "eb693ec8252cd630102fd0d0fb7c3485"

It's documented here: Ruby 1.9.3 - Module: SecureRandom (lib/securerandom.rb)

Solution 4

Well, I figured it out. Apparently there is a builtin (?) function called rand:

rand(n + 1)

If someone answers with a more detailed answer, I'll mark that as the correct answer.

Solution 5

What about this?

n = 3
(0..n).to_a.sample
Share:
546,169
Mark A. Nicolosi
Author by

Mark A. Nicolosi

Updated on September 23, 2021

Comments

  • Mark A. Nicolosi
    Mark A. Nicolosi over 2 years

    How do I generate a random number between 0 and n?

  • Christoph Schiessl
    Christoph Schiessl over 15 years
    Yes, it's builtin in the Kernel module.
  • Alex B
    Alex B over 15 years
    What happens if you don't call srand()?
  • Dan Rosenstark
    Dan Rosenstark over 14 years
    Isn't this terribly non-ruby-like? I thought everything is an object, least-surprise and that...
  • Zerrets
    Zerrets about 14 years
    srand is automatically called with the seed being from the current time if it wasn't already called.
  • Marc-André Lafortune
    Marc-André Lafortune almost 14 years
    @yar: It is a bit "perlish". Now Ruby has it's Random class (see my answer)
  • VonC
    VonC almost 14 years
    Excellent! +1. I have completed my own answer to reflect that new feature (and mentioning your contribution with Bug #3104 ;) ).
  • Marc-André Lafortune
    Marc-André Lafortune almost 14 years
    @yar: My backports gem is simply a collection of methods that are new to RUby 1.8.7, 1.9.1, 1.9.2, but implemented in Ruby. I use RubySpec to insure that the results are compatible with Ruby.
  • Dan Rosenstark
    Dan Rosenstark almost 14 years
    @Marc-André Lafortune, thanks for that. It's always been strange to me how much of Ruby is implemented in non-Ruby (C or whatever) due to speed requirements. But them's the breaks
  • Marc-André Lafortune
    Marc-André Lafortune almost 14 years
    @yar: Until there is a really good implementation of Ruby, the builtin Random class will perform much better than my compatible Ruby version... It's the goal of Rubinius to minimize the C++ code without a big loss of performance.
  • Dan Rosenstark
    Dan Rosenstark almost 14 years
    @Marc-André Lafortune, while we're here: is JRuby not a good implementation? I could be totally off-base and you'll say, "no it's the worst of all."
  • Marc-André Lafortune
    Marc-André Lafortune almost 14 years
    @yar: It is! But the mersenne twister in Ruby will spend most of the time in function calls and very little time doing the basic calculations. By a good implementation, I meant one that could inline those dynamic calls very well (which I don't think the JVM can do). Rubinius aims to do that. I haven't done any performance testing, though, so I'm speculating :-)
  • Dan Rosenstark
    Dan Rosenstark almost 14 years
    Rubinius, eh? I'll keep my eye on that one, I see it's right in line with what we're talking about. Fascinating in any case... thanks for the chat.
  • Juanda
    Juanda over 13 years
    Shorter version would be Random.new.rand(0..100)
  • Marc-André Lafortune
    Marc-André Lafortune almost 13 years
    @Juanda: Actually my example is in two lines because it's a terrible idea to call Random.new all the time. I've edited my answer
  • Marc-André Lafortune
    Marc-André Lafortune almost 13 years
    @VonC: It's great you edited your answer to mention the new Random class, but it's a terrible idea to call Random.new multiple times like in your example. I've edited my answer to state that.
  • VonC
    VonC almost 13 years
    @Marc-André: true, I have edited this answer and again referred to yours ;)
  • horseyguy
    horseyguy almost 13 years
    Random.rand(10..42) does not work. The Random.rand class method does not accept a range. (Ruby 1.9.2p180)
  • horseyguy
    horseyguy almost 13 years
    Random.rand does not accept a range, and so this code does not work: Random.rand(20..30), I am running on 1.9.2p180.
  • horseyguy
    horseyguy almost 13 years
    also the top-level rand method does not accept a range! how the heck did you get 74 points when your code is totally broken?!
  • VonC
    VonC almost 13 years
    @banister: that is strange, according to the current implementation, it (i.e: Random.rand) should support Range: redmine.ruby-lang.org/projects/ruby-19/repository/entry/…
  • horseyguy
    horseyguy almost 13 years
    @VonC, im pretty sure that's the docs for the Random#rand instance_method you're looking at there ;). For some reason the Random.rand class method behaves differently to the Random#rand instance method in this case
  • VonC
    VonC almost 13 years
    @banister: very good point (that 'static' there through me off). I have edited the answer to reflect your remark. To answer your other question "how the heck did you get 74 points when your code is totally broken?!", it is because up until less than a month ago, this answer contained "Random.new.rand(20..30), ie instance method rand ;) The recent edit in Marc-André's answer prompted me to update (a bit too quickly) that code in order to use the class method.
  • horseyguy
    horseyguy almost 13 years
    @VonC ah :) sorry if i was a bit harsh, it just surprised me
  • Marc-André Lafortune
    Marc-André Lafortune almost 13 years
    @banister: wow, I was convinced that the new api (rand with range, bytes, etc...) was available directly through the Random object. rand with range will be in 1.9.3, and I'll make a feature request for bytes. I've edited my answer
  • Batkins
    Batkins over 11 years
    I believe the range option is only available in ruby 1.9.3+. It didn't work in 1.9.2 when I tried at least.
  • Sam
    Sam over 10 years
    Also you can follow this blog for step by step very clear picture over random nos in ruby; sitepoint.com/tour-random-ruby
  • onurozgurozkan
    onurozgurozkan over 10 years
    What about if you need 4 digits random number?
  • Ajedi32
    Ajedi32 over 9 years
    Random.rand does accept a range, actually. (Since 1.9.3, I believe.)
  • digitalextremist
    digitalextremist almost 9 years
    Link to game guessing 10 numbers is gone.
  • JayTarka
    JayTarka over 8 years
    onurozgurozkan I presume SecureRandom.random_number(1000..9999)
  • mwp
    mwp over 8 years
    SecureRandom.random_number() doesn't take a range, so no. You would probably want something like SecureRandom.random_number(10_000) (for 0-9999) or SecureRandom.random_number(9_000)+1_000 (for 1000-9999).
  • Jesse Farmer
    Jesse Farmer almost 8 years
    Random.rand(1000..9999)
  • Travis
    Travis about 7 years
    It should be noted that generating an array of numbers like this solution provides has terrible performance on large ranges as it's O(n) while rand is O(1).
  • Eric Duminil
    Eric Duminil about 6 years
    @DanRosenstark: 8 years later... method(:rand) outputs #<Method: Object(Kernel)#rand>. So rand is a Kernel method, available to every Object. You can call self.send(:rand, 0..10) if it makes you feel better.
  • Greg
    Greg almost 5 years
    range.to_a.sample is an awful idea when the sample is big.
  • Camille Goudeseune
    Camille Goudeseune over 4 years
    If you must make an entire array, at least replace .shuffle.first with .sample!