How to resolve the algorithm Average loop length step by step in the Ruby programming language
How to resolve the algorithm Average loop length step by step in the Ruby programming language
Table of Contents
Problem Statement
Let f be a uniformly-randomly chosen mapping from the numbers 1..N to the numbers 1..N (note: not necessarily a permutation of 1..N; the mapping could produce a number in more than one way or not at all). At some point, the sequence 1, f(1), f(f(1))... will contain a repetition, a number that occurring for the second time in the sequence.
Write a program or a script that estimates, for each N, the average length until the first such repetition. Also calculate this expected length using an analytical formula, and optionally compare the simulated result with the theoretical one.
This problem comes from the end of Donald Knuth's Christmas tree lecture 2011. Example of expected output:
Let's start with the solution:
Step by Step solution about How to resolve the algorithm Average loop length step by step in the Ruby programming language
The provided Ruby code demonstrates how to calculate the average number of random numbers that need to be generated until one of them is repeated for a given range n
. It also compares these empirical averages with their expected values derived from mathematical analysis.
Here's a detailed breakdown of the code:
-
Extending the Integer class:
- The code extends the
Integer
class with afactorial
method that calculates the factorial of the integer. This method is used later in the analytical calculation of expected values.
- The code extends the
-
rand_until_rep
method:- This method generates random numbers within a given range
n
and keeps track of the generated numbers in arands
hash. - It continues generating random numbers until a repeated number is encountered.
- The number of random numbers generated until a repetition occurs is returned as the result.
- This method generates random numbers within a given range
-
Main Execution:
- The code sets
runs
to 1,000,000, indicating how many times the experiment should be run for each value ofn
.
- The code sets
-
Table Header:
- The code prints a table header with the following columns: "N" (range), "average" (empirical average), "exp." (expected value), and "diff" (percentage difference between empirical average and expected value).
-
Loop Over Different
n
Values:- The code iterates over
n
values from 1 to 20. - For each
n
, it calculates the empirical average by running therand_until_rep
methodruns
times and accumulates the number of random numbers generated until repetition in thesum_of_runs
variable. The average is then calculated by dividing thesum_of_runs
byruns
.
- The code iterates over
-
Expected Value Calculation:
- The expected value is calculated using mathematical analysis. It computes the sum of probabilities for each random number within the range
n
, taking into account the number of possible repetitions for each random number.
- The expected value is calculated using mathematical analysis. It computes the sum of probabilities for each random number within the range
-
Printing Results:
- The code prints the
n
value, the empirical average, the expected value, and the percentage difference between the empirical average and expected value for eachn
value.
- The code prints the
The output of the code is a table showing the empirical averages, expected values, and their percentage differences for different n
values. This table helps analyze the behavior of the rand_until_rep
method and compare its empirical results with theoretical expectations.
Source code in the ruby programming language
class Integer
def factorial
self == 0 ? 1 : (1..self).inject(:*)
end
end
def rand_until_rep(n)
rands = {}
loop do
r = rand(1..n)
return rands.size if rands[r]
rands[r] = true
end
end
runs = 1_000_000
puts " N average exp. diff ",
"=== ======== ======== ==========="
(1..20).each do |n|
sum_of_runs = runs.times.inject(0){|sum, _| sum += rand_until_rep(n)}
avg = sum_of_runs / runs.to_f
analytical = (1..n).inject(0){|sum, i| sum += (n.factorial / (n**i).to_f / (n-i).factorial)}
puts "%3d %8.4f %8.4f (%8.4f%%)" % [n, avg, analytical, (avg/analytical - 1)*100]
end
You may also check:How to resolve the algorithm Write language name in 3D ASCII step by step in the Raku programming language
You may also check:How to resolve the algorithm Prime conspiracy step by step in the Java programming language
You may also check:How to resolve the algorithm Web scraping step by step in the PureBasic programming language
You may also check:How to resolve the algorithm Binary search step by step in the 360 Assembly programming language
You may also check:How to resolve the algorithm Multi-dimensional array step by step in the Objeck programming language