Add all the A tasks

This commit is contained in:
Ingy döt Net 2013-04-10 14:58:50 -07:00
parent 2dd7375f96
commit 051504d65b
1608 changed files with 18584 additions and 0 deletions

View file

@ -0,0 +1,32 @@
Let <code>f</code> 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 <code>1, f(1), f(f(1))...</code> will contain a <em>repetition</em>, a number that occurring for the second time in the sequence.
Write a program or a script that estimates, for each <code>N</code>, 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 [http://www.youtube.com/watch?v=cI6tt9QfRdo Christmas tree lecture 2011].
Example of expected output:
<pre> N average analytical (error)
=== ========= ============ =========
1 1.0000 1.0000 ( 0.00%)
2 1.4992 1.5000 ( 0.05%)
3 1.8784 1.8889 ( 0.56%)
4 2.2316 2.2188 ( 0.58%)
5 2.4982 2.5104 ( 0.49%)
6 2.7897 2.7747 ( 0.54%)
7 3.0153 3.0181 ( 0.09%)
8 3.2429 3.2450 ( 0.07%)
9 3.4536 3.4583 ( 0.14%)
10 3.6649 3.6602 ( 0.13%)
11 3.8091 3.8524 ( 1.12%)
12 3.9986 4.0361 ( 0.93%)
13 4.2074 4.2123 ( 0.12%)
14 4.3711 4.3820 ( 0.25%)
15 4.5275 4.5458 ( 0.40%)
16 4.6755 4.7043 ( 0.61%)
17 4.8877 4.8579 ( 0.61%)
18 4.9951 5.0071 ( 0.24%)
19 5.1312 5.1522 ( 0.41%)
20 5.2699 5.2936 ( 0.45%)</pre>

View file

@ -0,0 +1,53 @@
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Numerics.Generic_Elementary_Functions;
with Ada.Numerics.Discrete_Random;
procedure Avglen is
package IIO is new Ada.Text_IO.Integer_IO (Positive); use IIO;
package LFIO is new Ada.Text_IO.Float_IO (Long_Float); use LFIO;
subtype FactN is Natural range 0..20;
TESTS : constant Natural := 1_000_000;
function Factorial (N : FactN) return Long_Float is
Result : Long_Float := 1.0;
begin
for I in 2..N loop Result := Result * Long_Float(I); end loop;
return Result;
end Factorial;
function Analytical (N : FactN) return Long_Float is
Sum : Long_Float := 0.0;
begin
for I in 1..N loop
Sum := Sum + Factorial(N) / Factorial(N - I) / Long_Float(N)**I;
end loop;
return Sum;
end Analytical;
function Experimental (N : FactN) return Long_Float is
subtype RandInt is Natural range 1..N;
package Random is new Ada.Numerics.Discrete_Random(RandInt);
seed : Random.Generator;
Num : RandInt;
count : Natural := 0;
bits : array(RandInt'Range) of Boolean;
begin
Random.Reset(seed);
for run in 1..TESTS loop
bits := (others => false);
for I in RandInt'Range loop
Num := Random.Random(seed); exit when bits(Num);
bits(Num) := True; count := count + 1;
end loop;
end loop;
return Long_Float(count)/Long_Float(TESTS);
end Experimental;
A, E, err : Long_Float;
begin
Put_Line(" N avg calc %diff");
for I in 1..20 loop
A := Analytical(I); E := Experimental(I); err := abs(E-A)/A*100.0;
Put(I, Width=>2); Put(E ,Aft=>4, exp=>0); Put(A, Aft=>4, exp=>0);
Put(err, Fore=>3, Aft=>3, exp=>0); New_line;
end loop;
end Avglen;

View file

@ -0,0 +1,56 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
#define MAX_N 20
#define TIMES 1000000
double factorial(int n) {
double f = 1;
int i;
for (i = 1; i <= n; i++) f *= i;
return f;
}
double expected(int n) {
double sum = 0;
int i;
for (i = 1; i <= n; i++)
sum += factorial(n) / pow(n, i) / factorial(n - i);
return sum;
}
int randint(int n) {
int r, rmax = RAND_MAX / n * n;
while ((r = rand()) >= rmax);
return r / (RAND_MAX / n);
}
int test(int n, int times) {
int i, count = 0;
for (i = 0; i < times; i++) {
int x = 1, bits = 0;
while (!(bits & x)) {
count++;
bits |= x;
x = 1 << randint(n);
}
}
return count;
}
int main(void) {
srand(time(0));
puts(" n\tavg\texp.\tdiff\n-------------------------------");
int n;
for (n = 1; n <= MAX_N; n++) {
int cnt = test(n, TIMES);
double avg = (double)cnt / TIMES;
double theory = expected(n);
double diff = (avg / theory - 1) * 100;
printf("%2d %8.4f %8.4f %6.3f%%\n", n, avg, theory, diff);
}
return 0;
}

View file

@ -0,0 +1,27 @@
from __future__ import division # Only necessary for Python 2.X
from math import factorial
from random import randrange
MAX_N = 20
TIMES = 1000000
def analytical(n):
return sum(factorial(n) / pow(n, i) / factorial(n -i) for i in range(1, n+1))
def test(n, times):
count = 0
for i in range(times):
x, bits = 1, 0
while not (bits & x):
count += 1
bits |= x
x = 1 << randrange(n)
return count / times
if __name__ == '__main__':
print(" n\tavg\texp.\tdiff\n-------------------------------")
for n in range(1, MAX_N+1):
avg = test(n, TIMES)
theory = analytical(n)
diff = (avg / theory - 1) * 100
print("%2d %8.4f %8.4f %6.3f%%" % (n, avg, theory, diff))

View file

@ -0,0 +1,36 @@
/*REXX program to read a config file and assign VARs as found within. */
numeric digits 10000 /*be able to calculate !(runs). */
parse arg runs tests seed .
if runs ==',' | runs =='' then runs = 40 /*num of runs. */
if tests ==',' | tests =='' then tests = 1000000 /*num of trials.*/
if seed\==',' & seed\=='' then call random ,,seed /*repeatability?*/
numeric digits max(9,length(!(runs))) /*set NUMERIC digits for !(runs).*/
say right( runs, 24) 'runs' /*display # of runs we're using*/
say right( tests, 24) 'tests' /* " " " tests " " */
say right( digits(), 24) 'digits' /* " " " digits " " */
say
say ' N average exact % error' /*headers & pad.*/
h= ' '; say h; pad=left('',3)
do #=1 for runs; ##=right(#,9) /*## is used for indenting output*/
a= format(exact(#) ,,4) /*use 4 digits past decimal point*/
e= format(exper(#) ,,4) /* " " " " " " */
err= format(abs(e-a)*100/a ,,4) /* " " " " " " */
if err=0 then err=err/1 /*present a clean & concise zero.*/
say ## pad e pad a pad err /*display a line of statistics. */
end /*#*/
say h /*display the final header bar. */
exit /*stick a fork in it, we're done.*/
/*──────────────────────────────────! subroutine────────────────────────*/
!: procedure; !=1; do j=2 to arg(1); !=!*j; end; return !
/*──────────────────────────────────EXACT subroutine────────────────────*/
exact: parse arg x; s=0; do j=1 for x; s=s+!(x)/!(x-j)/x**j; end; return s
/*──────────────────────────────────EXPER subroutine────────────────────*/
exper: parse arg n
k=0; do tests; !.=0 /*repeat TESTS times, reset found*/
!.=0 /*stemmed array: expected results*/
do n; r=random(1,n); if !.r then leave
!.r=1; k=k+1 /*bump the ctr. */
end /*n*/
end /*tests*/
return k/tests

View file

@ -0,0 +1,40 @@
# Generate a list of the numbers increasing from $a to $b
proc range {a b} {
for {set result {}} {$a <= $b} {incr a} {lappend result $a}
return $result
}
# Computing the expected value analytically
proc tcl::mathfunc::factorial n {
::tcl::mathop::* {*}[range 2 $n]
}
proc Analytical {n} {
set sum 0.0
foreach x [range 1 $n] {
set sum [expr {$sum + factorial($n) / factorial($n-$x) / double($n)**$x}]
}
return $sum
}
# Determining an approximation to the value experimentally
proc Experimental {n numTests} {
set count 0
set u0 [lrepeat $n 1]
foreach run [range 1 $numTests] {
set unseen $u0
for {set i 0} {[lindex $unseen $i]} {incr count} {
lset unseen $i 0
set i [expr {int(rand()*$n)}]
}
}
return [expr {$count / double($numTests)}]
}
# Tabulate the results in exactly the original format
puts " N average analytical (error)"
puts "=== ========= ============ ========="
foreach n [range 1 20] {
set a [Analytical $n]
set e [Experimental $n 100000]
puts [format "%3d %9.4f %12.4f (%6.2f%%)" $n $e $a [expr {abs($e-$a)/$a*100.0}]]
}