Generating Random Numbers in Ruby


#1

Sometimes I need to generate random numbers in Sketchup, but the Rubocop Sketchup cops warn that this can cause terrible performance, particularly on Windows. So far it has seemed like it can be slow, but I haven’t actually profiled it.

Previously, ThomThom and others have warned about Sketchup freezing for multiple minutes if using OpenSSL based solutions.

So here are some alternatives to SecureRandom and OpenSSL random number generation:

require 'benchmark'
require 'securerandom'
require 'base64'

iterations = 10_000
Benchmark.bmbm do |bm|
  bm.report('Securerandom') do
    iterations.times do 
      SecureRandom.urlsafe_base64
    end
  end
  bm.report('base64') do
    iterations.times do
      Base64.urlsafe_encode64(Random.new.bytes(16))
    end
  end
  bm.report('fake random') do
    iterations.times do
      rand(0x1000000000000000000000000000000000000000).to_s(36)
    end
  end
end

2018-08-29_19-16-59

My results show that SecureRandom seems to be passably fast in Ruby2.2 enabled Sketchup versions on Windows, though I haven’t tested others. At this point I’m not sure the suggestion to avoid it is still valid on newer versions of Sketchup. An alternative, using Random.new.bytes(16), however, performs much worse and should probably be added to recommendations to avoid.

Meanwhile, the real star is using the native Kernel#rand with an enormous number and then converting it to a base36 string. I found this trick in the Rails core code.

Try it yourself and see.

Choices are to generate a safe, 128-bit GUID that would be suitable anywhere, (uses ASCII and urlsafe characters).


#2

It depends on what you need the random numbers for. For just “arbitrary” numbers, fast pseudo-random numbers should be good enough.


#3

@Aerilius makes a good point: the expensive random number generators are geared toward creating unpredictable sequences , which is quite a different thing from creating a single unpredictable number.


#4

Is your use case encrypting confidential data or more in the area of randomly placing windows in a facade? For architecture I’ve been using a simple rand and never had problems with patterns that I can spot with my own eyes.


#5

This is unlikely to come up for too many people, but the use case is to keep track of many atomic pieces of data that may be shared between multiples computers.

The fast pseudo-random numbers work well for this case, and I can reasonably sure they won’t overlap given that 128 bits should be enough to generate a GUID without collision.


#6

Right! Random number generators for use in encryption and the like are subject to stringent statistical analyses to make sure that it is effectively impossible to predict their pattern, hence to break a code. But if you aren’t needing that level of security, much simpler generators are adequate. Humans are not good at seeing the sort of minuscule correlations that spoil a code. So unless you are expecting the NSA or GRU (or other skilled hackers) to attack your method, I’d use whatever is fastest.


#7

Yes for encryption this would NOT be sufficient, so the simpler random strings work well. If someone wanted to use encryption probably only the methods in SecureRandom or OpenSSL would be acceptable even with the possible old OpenSSL version penalties.


#8

The lag/freeze issue with OpenSSL in Ruby on Windows differ greatly on how much memory the application have previously or currently consumed. From a fresh start it’s much smaller. But after loading a larger file, the effect increases.


#9

Oh, thanks for the clarification.


#10

Ah. Then your real concern is to avoid “collisions”, that is, getting the same value twice. A random number generator does not necessarily guarantee that property, as the same value recurring is legal so long as there was no way to predict that it would happen. You need something more like a GUID (globally unique id).

Hash structures usually allow for collisions by making each value lead to an array of “buckets” in case multiple entries hash to the same value. It requires a secondary identifier to pick which bucket you actually need.


#11

The lack of patterns is usually a proof of a process that is not truly random. Facades require quite careful composition to “look random” in an aesthetically pleasing way


#12

I would say it depends on what you mean by pattern. True randomness creates sequences that can be interpreted as pattern (2, 3, sometimes 4 and even more identical die rolls, or a facade weighted to one side or with objects in clusters etc), but with some experience I’d rather say the lack of such sequences is a pattern.

I can often see these patterns in man made “random” compositions, e.g. how the designer deliberately has evened out things to avoid clusters or asymmetry. In a way this bugs me a bit, and I prefer the aesthetics of a more true randomness.


#13

Right, but from my research a 128-bit random number is “guaranteed” against collision in that the possibility is so vanishingly small as to not require checking for it. Of course, it’s still possible, but unlikely to happen before the heat death of the universe :slight_smile:

Some professors apparently do this to show how randomness often looks like a pattern, e.g. a list of coin tosses H (Heads) or T (Tails) will often end up with long sequences like HTTTTTTTTHTHTTTHHH and students naive to this will expect a much more even distribution.


#14

As one of my professors once quipped, “And when it happens we open a bottle of champagne because we’ve just observed an event of probability zero!”


#15

My dad told me about a professor (don’t know if it was his or someone elses) who started a course, likely in statistical analysis or something similar, by tasking students to do a hundred die rolls, document them and hand it in. With just a quick glance at each paper he could tell students they had cheated (made up numbers because its quicker) and had to do it again, properly this time :stuck_out_tongue: . Randomness is fascinating!


#16

The Lisp version used in AutoCad didn’t have a random number function so I cheated by taking the last digit of the current time (in milliseconds). To my purposes (scattering blocks) that was random enough.


#17

Love it.

That’s the story I was thinking of!

That is a great tactic. A lot of random generators use a clock cycle and mix it in with several other random sources. One of my favorite is the Cloudflare lava lamp randomness generator.


#18

Turbulence of various sort is a great source for randomness. Another one I’ve read about was an extra card you can install to your computer (much like graphic card or sound card) that detected the universal background radiation and used that to create random numbers.


#19

That’s more “bio” (because we are always exposed to it) than taking a radio-active Americium souvenir from the physics lab!


#20

Or, you could use a webservice for this, like: https://www.random.org/
En example would be to GET: https://www.random.org/integers/?num=1&min=1&max=10000&col=1&base=10&format=plain&rnd=new to receive a random number between 1 and 10.000.

In ruby this would be something like:


min = 1
max = 10000

request = Sketchup::Http::Request.new("https://www.random.org/integers/?num=1&min=#{min}&max=#{max}&col=1&base=10&format=plain&rnd=new", Sketchup::Http::GET)

request.start do |request, response|
  puts "body: #{response.body}"
end

Other options and endpoints are available.