⚠️ Warning: This is a draft ⚠️

This means it might contain formatting issues, incorrect code, conceptual problems, or other severe issues.

If you want to help to improve and eventually enable this page, please fork RosettaGit's repository and open a merge request on GitHub.

{{task|Probability and statistics}} Given a mapping between items and their required probability of occurrence, generate a million items ''randomly'' subject to the given probabilities and compare the target probability of occurrence versus the generated values.

The total of all the probabilities should equal one. (Because floating point arithmetic is involved, this is subject to rounding errors).

Use the following mapping to test your programs:

```
aleph   1/5.0
beth    1/6.0
gimel   1/7.0
daleth  1/8.0
he      1/9.0
waw     1/10.0
zayin   1/11.0
```

• [[Random number generator (device)]]

```with Ada.Numerics.Float_Random;  use Ada.Numerics.Float_Random;

procedure Random_Distribution is
Trials : constant := 1_000_000;
type Outcome is (Aleph, Beth, Gimel, Daleth, He, Waw, Zayin, Heth);
Pr : constant array (Outcome) of Uniformly_Distributed :=
(1.0/5.0, 1.0/6.0, 1.0/7.0, 1.0/8.0, 1.0/9.0, 1.0/10.0, 1.0/11.0, 1.0);
Samples : array (Outcome) of Natural := (others => 0);
Value   : Uniformly_Distributed;
Dice    : Generator;
begin
for Try in 1..Trials loop
Value := Random (Dice);
for I in Pr'Range loop
if Value <= Pr (I) then
Samples (I) := Samples (I) + 1;
exit;
else
Value := Value - Pr (I);
end if;
end loop;
end loop;
-- Printing the results
for I in Pr'Range loop
Put (Outcome'Image (I) & Character'Val (9));
Put (Float'Image (Float (Samples (I)) / Float (Trials)) & Character'Val (9));
if I = Heth then
Put_Line (" rest");
else
Put_Line (Uniformly_Distributed'Image (Pr (I)));
end if;
end loop;
end Random_Distribution;
```

Sample output:

```
ALEPH    2.00167E-01     2.00000E-01
BETH     1.67212E-01     1.66667E-01
GIMEL    1.42290E-01     1.42857E-01
DALETH   1.24186E-01     1.25000E-01
HE       1.11455E-01     1.11111E-01
WAW      1.00325E-01     1.00000E-01
ZAYIN    9.10220E-02     9.09091E-02
HETH     6.33430E-02     rest

```

ALGOL 68

{{trans|C}}

{{works with|ALGOL 68|Revision 1 - no extensions to language used}}

{{works with|ALGOL 68G|Any - tested with release [http://sourceforge.net/projects/algol68/files/algol68g/algol68g-1.18.0/algol68g-1.18.0-9h.tiny.el5.centos.fc11.i386.rpm/download 1.18.0-9h.tiny]}} {{wont work with|ELLA ALGOL 68|Any (with appropriate job cards) - tested with release [http://sourceforge.net/projects/algol68/files/algol68toc/algol68toc-1.8.8d/algol68toc-1.8-8d.fc9.i386.rpm/download 1.8-8d] - due to extensive use of FORMATted transput}}

```INT trials = 1 000 000;

MODE LREAL = LONG REAL;

MODE ITEM = STRUCT(
STRING name,
INT prob count,
LREAL expect,
mapping
);
INT col width = 9;
FORMAT real repr = \$g(-col width+1, 6)\$,
item repr = \$"Name: "g", Prob count: "g(0)", Expect: "f(real repr)", Mapping: ", f(real repr)l\$;

[8]ITEM items := (
( "aleph",  0, ~, ~ ),
( "beth",   0, ~, ~ ),
( "gimel",  0, ~, ~ ),
( "daleth", 0, ~, ~ ),
( "he",     0, ~, ~ ),
( "waw",    0, ~, ~ ),
( "zayin",  0, ~, ~ ),
( "heth",   0, ~, ~ )
);

main:
(
LREAL offset = 5; # const #

# initialise items #
LREAL total sum := 0;
FOR i FROM LWB items TO UPB items - 1 DO
expect OF items[i] := 1/(i-1+offset);
total sum +:= expect OF items[i]
OD;
expect OF items[UPB items] := 1 - total sum;

mapping OF items[LWB items] := expect OF items[LWB items];
FOR i FROM LWB items + 1 TO UPB items DO
mapping OF items[i] := mapping OF items[i-1] + expect OF items[i]
OD;

# printf((item repr, items)) #

# perform the sampling #
PROC sample = (REF[]LREAL mapping)INT:(
INT out;
LREAL rand real = random;
FOR j FROM LWB items TO UPB items DO
IF rand real < mapping[j] THEN
out := j;
done
FI
OD;
done: out
);

FOR i TO trials DO
prob count OF items[sample(mapping OF items)] +:= 1
OD;

FORMAT indent = \$17k\$;

# print the results #
printf((\$"Trials: "g(0)l\$, trials));
printf((\$"Items:"\$,indent));
FOR i FROM LWB items TO UPB items DO printf((\$gn(col width)k" "\$, name OF items[i])) OD;
printf((\$l"Target prob.:"\$, indent, \$f(real repr)" "\$, expect OF items));
printf((\$l"Attained prob.:"\$, indent));
FOR i FROM LWB items TO UPB items DO printf((\$f(real repr)" "\$, prob count OF items[i]/trials)) OD;
printf(\$l\$)
)
```

Sample output:

```
Trials: 1000000
Items:          aleph    beth     gimel    daleth   he       waw      zayin    heth
Target prob.:   0.200000 0.166667 0.142857 0.125000 0.111111 0.100000 0.090909 0.063456
Attained prob.: 0.199987 0.166917 0.142531 0.124203 0.111338 0.099702 0.091660 0.063662

```

AutoHotkey

contributed by Laszlo on the ahk [http://www.autohotkey.com/forum/post-276279.html#276279 forum]

```s1 := "aleph",   p1 := 1/5.0                       ; Input
s2 := "beth",    p2 := 1/6.0
s3 := "gimel",   p3 := 1/7.0
s4 := "daleth",  p4 := 1/8.0
s5 := "he",      p5 := 1/9.0
s6 := "waw",     p6 := 1/10.0
s7 := "zayin",   p7 := 1/11.0
s8 := "heth",    p8 := 1-p1-p2-p3-p4-p5-p6-p7
n := 8, r0 := 0, r%n% := 1                         ; auxiliary data

Loop % n-1
i := A_Index-1, r%A_Index% := r%i% + p%A_Index% ; cummulative distribution

Loop 1000000 {
Random R, 0, 1.0
Loop %n%                                        ; linear search
If (R < r%A_Index%) {
c%A_Index%++
Break
}
}
; Output
Loop %n%
t .= s%A_Index% "`t" p%A_Index% "`t" c%A_Index%*1.0e-6 "`n"
Msgbox %t%

/*
output:
---------------------------
aleph  0.200000   0.199960
beth   0.166667   0.166146
gimel  0.142857   0.142624
daleth 0.125000   0.124924
he     0.111111   0.111226
waw    0.100000   0.100434
zayin  0.090909   0.091344
heth   0.063456   0.063342
---------------------------
*/
```

AWK

```#!/usr/bin/awk -f

BEGIN {
ITERATIONS = 1000000
delete symbMap
delete probMap
delete counts
initData();

for (i = 0; i < ITERATIONS; i++) {
distribute(rand())
}
showDistributions()

exit
}

function distribute(rnd,    cnt, symNum, sym, symPrb) {
cnt = length(symbMap)
for (symNum = 1; symNum <= cnt; symNum++) {
sym = symbMap[symNum];
symPrb = probMap[sym];
rnd -= symPrb;
if (rnd <= 0) {
counts[sym]++
return;
}
}
}

function showDistributions(    s, sym, prb, actSum, expSum, totItr) {
actSum = 0.0
expSum = 0.0
totItr = 0
printf "%-7s  %-7s  %-5s  %-5s\n", "symb", "num.", "act.", "expt."
print  "-------  -------  -----  -----"
for (s = 1; s <= length(symbMap); s++) {
sym = symbMap[s]
prb = counts[sym]/ITERATIONS
actSum += prb
expSum += probMap[sym]
totItr += counts[sym]
printf "%-7s  %7d  %1.3f  %1.3f\n", sym, counts[sym], prb, probMap[sym]
}
print  "-------  -------  -----  -----"
printf "Totals:  %7d  %1.3f  %1.3f\n", totItr, actSum, expSum
}

function initData(    sym) {
srand()

probMap["aleph"]  = 1.0 / 5.0
probMap["beth"]   = 1.0 / 6.0
probMap["gimel"]  = 1.0 / 7.0
probMap["daleth"] = 1.0 / 8.0
probMap["he"]     = 1.0 / 9.0
probMap["waw"]    = 1.0 / 10.0
probMap["zyin"]   = 1.0 / 11.0
probMap["heth"]   = 1759.0 / 27720.0

symbMap[1] = "aleph"
symbMap[2] = "beth"
symbMap[3] = "gimel"
symbMap[4] = "daleth"
symbMap[5] = "he"
symbMap[6] = "waw"
symbMap[7] = "zyin"
symbMap[8] = "heth"

for (sym in probMap)
counts[sym] = 0;
}

```

Example output:

symb num. act. expt.

aleph 200598 0.201 0.200 beth 166317 0.166 0.167 gimel 142391 0.142 0.143 daleth 125051 0.125 0.125 he 110658 0.111 0.111 waw 100464 0.100 0.100 zyin 90649 0.091 0.091 heth 63872 0.064 0.063

Totals: 1000000 1.000 1.000

Rounding off makes the results look perfect.

BBC BASIC

```      DIM item\$(7), prob(7), cnt%(7)
item\$() = "aleph","beth","gimel","daleth","he","waw","zayin","heth"
prob()  = 1/5.0, 1/6.0, 1/7.0, 1/8.0, 1/9.0, 1/10.0, 1/11.0, 1759/27720
IF ABS(SUM(prob())-1) > 1E-6 ERROR 100, "Probabilities don't sum to 1"

FOR trial% = 1 TO 1E6
r = RND(1)
p = 0
FOR i% = 0 TO DIM(prob(),1)
p += prob(i%)
IF r < p cnt%(i%) += 1 : EXIT FOR
NEXT
NEXT

@% = &2060A
PRINT "Item        actual    theoretical"
FOR i% = 0 TO DIM(item\$(),1)
PRINT item\$(i%), cnt%(i%)/1E6, prob(i%)
NEXT
```

'''Output:'''

```
Item        actual    theoretical
aleph       0.200306  0.200000
beth        0.165963  0.166667
gimel       0.143089  0.142857
daleth      0.125387  0.125000
he          0.111057  0.111111
waw         0.100098  0.100000
zayin       0.091031  0.090909
heth        0.063069  0.063456

```

C

```#include <stdio.h>
#include <stdlib.h>

/* pick a random index from 0 to n-1, according to probablities listed
in p[] which is assumed to have a sum of 1. The values in the probablity
list matters up to the point where the sum goes over 1 */
int rand_idx(double *p, int n)
{
double s = rand() / (RAND_MAX + 1.0);
int i;
for (i = 0; i < n - 1 && (s -= p[i]) >= 0; i++);
return i;
}

#define LEN 8
#define N 1000000
int main()
{
const char *names[LEN] = { "aleph", "beth", "gimel", "daleth",
"he", "waw", "zayin", "heth" };
double s, p[LEN] = { 1./5, 1./6, 1./7, 1./8, 1./9, 1./10, 1./11, 1e300 };
int i, count[LEN] = {0};

for (i = 0; i < N; i++) count[rand_idx(p, LEN)] ++;

printf("  Name  Count    Ratio Expected\n");
for (i = 0, s = 1; i < LEN; s -= p[i++])
printf("%6s%7d %7.4f%% %7.4f%%\n",
names[i], count[i],
(double)count[i] / N * 100,
((i < LEN - 1) ? p[i] : s) * 100);

return 0;
}
```

output Name Count Ratio Expected aleph 199928 19.9928% 20.0000% beth 166489 16.6489% 16.6667% gimel 143211 14.3211% 14.2857% daleth 125257 12.5257% 12.5000% he 110849 11.0849% 11.1111% waw 99935 9.9935% 10.0000% zayin 91001 9.1001% 9.0909% heth 63330 6.3330% 6.3456%

```

## C++

```cpp
#include <cstdlib>
#include <iostream>
#include <vector>
#include <utility>
#include <algorithm>
#include <ctime>
#include <iomanip>

int main( ) {
typedef std::vector<std::pair<std::string, double> >::const_iterator SPI ;
typedef std::vector<std::pair<std::string , double> > ProbType ;
ProbType probabilities ;
probabilities.push_back( std::make_pair( "aleph" , 1/5.0 ) ) ;
probabilities.push_back( std::make_pair( "beth" , 1/6.0 ) ) ;
probabilities.push_back( std::make_pair( "gimel" , 1/7.0 ) ) ;
probabilities.push_back( std::make_pair( "daleth" , 1/8.0 ) ) ;
probabilities.push_back( std::make_pair( "he" , 1/9.0 ) ) ;
probabilities.push_back( std::make_pair( "waw" , 1/10.0 ) ) ;
probabilities.push_back( std::make_pair( "zayin" , 1/11.0 ) ) ;
probabilities.push_back( std::make_pair( "heth" , 1759/27720.0 ) ) ;
std::vector<std::string> generated ; //for the strings that are generatod
std::vector<int> decider ; //holds the numbers that determine the choice of letters
for ( int i = 0 ; i < probabilities.size( ) ; i++ ) {
if ( i == 0 ) {
decider.push_back( 27720 * (probabilities[ i ].second) ) ;
}
else {
int number = 0 ;
for ( int j = 0 ; j < i ; j++ ) {
number +=  27720 * ( probabilities[ j ].second ) ;
}
number += 27720 * probabilities[ i ].second ;
decider.push_back( number ) ;
}
}
srand( time( 0 ) ) ;
for ( int i = 0 ; i < 1000000 ; i++ ) {
int randnumber = rand( ) % 27721 ;
int j = 0 ;
while ( randnumber > decider[ j ] )
j++ ;
generated.push_back( ( probabilities[ j ]).first ) ;
}
std::cout << "letter  frequency attained   frequency expected\n" ;
for ( SPI i = probabilities.begin( ) ; i != probabilities.end( ) ; i++ ) {
std::cout << std::left << std::setw( 8 ) << i->first ;
int found = std::count ( generated.begin( ) , generated.end( ) , i->first ) ;
std::cout << std::left << std::setw( 21 ) << found / 1000000.0 ;
std::cout << std::left << std::setw( 17 ) << i->second << '\n' ;
}
return 0 ;
}
```

Output:

```letter  frequency attained   frequency expected
aleph   0.200089             0.2
beth    0.16695              0.166667
gimel   0.142693             0.142857
daleth  0.124859             0.125
he      0.111258             0.111111
waw     0.099665             0.1
zayin   0.090654             0.0909091
heth    0.063832             0.063456
```
## C# {{trans|Java}} ```c# using System; class Program { static long TRIALS = 1000000L; private class Expv { public string name; public int probcount; public double expect; public double mapping; public Expv(string name, int probcount, double expect, double mapping) { this.name = name; this.probcount = probcount; this.expect = expect; this.mapping = mapping; } } static Expv[] items = { new Expv("aleph", 0, 0.0, 0.0), new Expv("beth", 0, 0.0, 0.0), new Expv("gimel", 0, 0.0, 0.0), new Expv("daleth", 0, 0.0, 0.0), new Expv("he", 0, 0.0, 0.0), new Expv("waw", 0, 0.0, 0.0), new Expv("zayin", 0, 0.0, 0.0), new Expv("heth", 0, 0.0, 0.0) }; static void Main(string[] args) { double rnum, tsum = 0.0; Random random = new Random(); for (int i = 0, rnum = 5.0; i < 7; i++, rnum += 1.0) { items[i].expect = 1.0 / rnum; tsum += items[i].expect; } items[7].expect = 1.0 - tsum; items[0].mapping = 1.0 / 5.0; for (int i = 1; i < 7; i++) items[i].mapping = items[i - 1].mapping + 1.0 / ((double)i + 5.0); items[7].mapping = 1.0; for (int i = 0; i < TRIALS; i++) { rnum = random.NextDouble(); for (int j = 0; j < 8; j++) if (rnum < items[j].mapping) { items[j].probcount++; break; } } Console.WriteLine("Trials: {0}", TRIALS); Console.Write("Items: "); for (int i = 0; i < 8; i++) Console.Write(items[i].name.PadRight(9)); Console.WriteLine(); Console.Write("Target prob.: "); for (int i = 0; i < 8; i++) Console.Write("{0:0.000000} ", items[i].expect); Console.WriteLine(); Console.Write("Attained prob.: "); for (int i = 0; i < 8; i++) Console.Write("{0:0.000000} ", (double)items[i].probcount / (double)TRIALS); Console.WriteLine(); } } ``` Output: ```txt Trials: 1000000 Items: aleph beth gimel daleth he waw zayin heth Target prob.: 0.200000 0.166667 0.142857 0.125000 0.111111 0.100000 0.090909 0.063456 Attained prob.: 0.199975 0.166460 0.142290 0.125510 0.111374 0.100018 0.090746 0.063627 ``` ## Clojure Works by first converting the provided Probability Distribution Function into a Cumulative Distribution Function, so that it can simply scan through the CDF list and return the current item as soon as the CDF at that point is greater than the random number generated. The code could be made more concise by skipping this step and instead tracking the whole PDF for each random number; but this code is both faster and more readable. It uses the language built-in (frequencies) to count the number of occurrences of each distinct name. Note that while we actually generate a sequence of num-trials random samples, the sequence is lazily generated and lazily consumed. This means that the program will scale to an arbitrarily-large num-trials with no ill effects, by throwing away elements it's already processed. ```Clojure (defn to-cdf [pdf] (reduce (fn [acc n] (conj acc (+ (or (last acc) 0) n))) [] pdf)) (defn choose [cdf] (let [r (rand)] (count (filter (partial > r) cdf)))) (def *names* '[aleph beth gimel daleth he waw zayin heth]) (def *pdf* (map double [1/5 1/6 1/7 1/8 1/9 1/10 1/11 1759/27720])) (let [num-trials 1000000 cdf (to-cdf *pdf*) indexes (range (count *names*)) ;; use integer key internally, not name expected (into (sorted-map) (zipmap indexes *pdf*)) actual (frequencies (repeatedly num-trials #(choose cdf)))] (doseq [[idx exp] expected] (println "Expected number of" (*names* idx) "was" (* num-trials exp) "and actually got" (actual idx)))) ``` ```txt Expected number of aleph was 200000.0 and actually got 199300 Expected number of beth was 166666.66666666672 and actually got 166291 Expected number of gimel was 142857.1428571429 and actually got 143297 Expected number of daleth was 125000.0 and actually got 125032 Expected number of he was 111111.11111111111 and actually got 111540 Expected number of waw was 100000.0 and actually got 100062 Expected number of zayin was 90909.09090909091 and actually got 90719 Expected number of heth was 63455.98845598846 and actually got 63759 ``` ## Common Lisp This is a straightforward, if a little verbose implementation based upon the Perl one. ```lisp (defvar *probabilities* '((aleph 1/5) (beth 1/6) (gimel 1/7) (daleth 1/8) (he 1/9) (waw 1/10) (zayin 1/11) (heth 1759/27720))) (defun calculate-probabilities (choices &key (repetitions 1000000)) (assert (= 1 (reduce #'+ choices :key #'second))) (labels ((make-ranges () (loop for (datum probability) in choices sum (coerce probability 'double-float) into total collect (list datum total))) (pick (ranges) (declare (optimize (speed 3) (safety 0) (debug 0))) (loop with random = (random 1.0d0) for (datum below) of-type (t double-float) in ranges when (< random below) do (return datum))) (populate-hash (ranges) (declare (optimize (speed 3) (safety 0) (debug 0))) (loop repeat (the fixnum repetitions) with hash = (make-hash-table) do (incf (the fixnum (gethash (pick ranges) hash 0))) finally (return hash))) (make-table-data (hash) (loop for (datum probability) in choices collect (list datum (float (/ (gethash datum hash) repetitions)) (float probability))))) (format t "Datum~10,2TOccured~20,2TExpected~%") (format t "~{~{~A~10,2T~F~20,2T~F~}~%~}" (make-table-data (populate-hash (make-ranges)))))) CL-USER> (calculate-probabilities *probabilities*) Datum Occured Expected ALEPH 0.200156 0.2 BETH 0.166521 0.16666667 GIMEL 0.142936 0.14285715 DALETH 0.124779 0.125 HE 0.111601 0.11111111 WAW 0.100068 0.1 ZAYIN 0.090458 0.09090909 HETH 0.063481 0.06345599 ``` ## D ### Basic Version ```d void main() { import std.stdio, std.random, std.string, std.range; enum int nTrials = 1_000_000; const items = "aleph beth gimel daleth he waw zayin heth".split; const pr = [1/5., 1/6., 1/7., 1/8., 1/9., 1/10., 1/11., 1759/27720.]; double[pr.length] counts = 0.0; foreach (immutable _; 0 .. nTrials) counts[pr.dice]++; writeln("Item Target prob Attained prob"); foreach (name, p, co; zip(items, pr, counts[])) writefln("%-7s %.8f %.8f", name, p, co / nTrials); } ``` {{out}} ```txt Item Target prob Attained prob aleph 0.20000000 0.19964000 beth 0.16666667 0.16753600 gimel 0.14285714 0.14283300 daleth 0.12500000 0.12515400 he 0.11111111 0.11074300 waw 0.10000000 0.10025800 zayin 0.09090909 0.09070400 heth 0.06345598 0.06313200 ``` ### A Faster Version ```d void main() { import std.stdio, std.random, std.algorithm, std.range; enum int nTrials = 1_000_000; const items = "aleph beth gimel daleth he waw zayin heth".split; const pr = [1/5., 1/6., 1/7., 1/8., 1/9., 1/10., 1/11., 1759/27720.]; double[pr.length] cumulatives = pr[]; foreach (immutable i, ref c; cumulatives[1 .. \$ - 1]) c += cumulatives[i]; cumulatives[\$ - 1] = 1.0; double[pr.length] counts = 0.0; auto rnd = Xorshift(unpredictableSeed); foreach (immutable _; 0 .. nTrials) counts[cumulatives[].countUntil!(c => c >= rnd.uniform01)]++; writeln("Item Target prob Attained prob"); foreach (name, p, co; zip(items, pr, counts[])) writefln("%-7s %.8f %.8f", name, p, co / nTrials); } ``` ## E This implementation converts the list of probabilities to sub-intervals of [0.0,1.0), then arranges those intervals in a binary tree for searching based on a random number input. It is rather verbose, due to using the tree rather than a linear search, and having code to print the tree (which was used to debug it). ```e pragma.syntax("0.9") ``` First, the algorithm: ```e /** Makes leaves of the binary tree */ def leaf(value) { return def leaf { to run(_) { return value } to __printOn(out) { out.print("=> ", value) } } } /** Makes branches of the binary tree */ def split(leastRight, left, right) { return def tree { to run(specimen) { return if (specimen < leastRight) { left(specimen) } else { right(specimen) } } to __printOn(out) { out.print(" ") out.indent().print(left) out.lnPrint("< ") out.print(leastRight) out.indent().lnPrint(right) } } } def makeIntervalTree(assocs :List[Tuple[any, float64]]) { def size :int := assocs.size() if (size > 1) { def midpoint := size // 2 return split(assocs[midpoint][1], makeIntervalTree(assocs.run(0, midpoint)), makeIntervalTree(assocs.run(midpoint))) } else { def [[value, _]] := assocs return leaf(value) } } def setupProbabilisticChoice(entropy, table :Map[any, float64]) { var cumulative := 0.0 var intervalTable := [] for value => probability in table { intervalTable with= [value, cumulative] cumulative += probability } def total := cumulative def selector := makeIntervalTree(intervalTable) return def probChoice { # Multiplying by the total helps correct for any error in the sum of the inputs to run() { return selector(entropy.nextDouble() * total) } to __printOn(out) { out.print("Probabilistic choice using tree:") out.indent().lnPrint(selector) } } } ``` Then the test setup: ```e def rosetta := setupProbabilisticChoice(entropy, def probTable := [ "aleph" => 1/5, "beth" => 1/6.0, "gimel" => 1/7.0, "daleth" => 1/8.0, "he" => 1/9.0, "waw" => 1/10.0, "zayin" => 1/11.0, "heth" => 0.063455988455988432, ]) var trials := 1000000 var timesFound := [].asMap() for i in 1..trials { if (i % 1000 == 0) { print(`\${i//1000} `) } def value := rosetta() timesFound with= (value, timesFound.fetch(value, fn { 0 }) + 1) } stdout.println() for item in probTable.domain() { stdout.print(item, "\t", timesFound[item] / trials, "\t", probTable[item], "\n") } ``` ## Elixir {{trans|Erlang}} ```elixir defmodule Probabilistic do @tries 1000000 @probs [aleph: 1/5, beth: 1/6, gimel: 1/7, daleth: 1/8, he: 1/9, waw: 1/10, zayin: 1/11, heth: 1759/27720] def test do trials = for _ <- 1..@tries, do: get_choice(@probs, :rand.uniform) IO.puts "Item Expected Actual" fmt = " ~-8s ~.6f ~.6f~n" Enum.each(@probs, fn {glyph,expected} -> actual = length(for ^glyph <- trials, do: glyph) / @tries :io.format fmt, [glyph, expected, actual] end) end defp get_choice([{glyph,_}], _), do: glyph defp get_choice([{glyph,prob}|_], ran) when ran < prob, do: glyph defp get_choice([{_,prob}|t], ran), do: get_choice(t, ran - prob) end Probabilistic.test ``` {{out}} ```txt Item Expected Actual aleph 0.200000 0.200676 beth 0.166667 0.166103 gimel 0.142857 0.142543 daleth 0.125000 0.125055 he 0.111111 0.111165 waw 0.100000 0.100439 zayin 0.090909 0.090894 heth 0.063456 0.063125 ``` ## Erlang {{trans|Java}} The optimized version of Java. ```erlang -module(probabilistic_choice). -export([test/0]). -define(TRIES, 1000000). test() -> Probs = [{aleph,1/5}, {beth,1/6}, {gimel,1/7}, {daleth,1/8}, {he,1/9}, {waw,1/10}, {zayin,1/11}, {heth,1759/27720}], random:seed(now()), Trials = [get_choice(Probs,random:uniform()) || _ <- lists:seq(1,?TRIES)], [{Glyph,Expected,(length([Glyph || Glyph_ <- Trials, Glyph_ == Glyph])/?TRIES)} || {Glyph,Expected} <- Probs]. get_choice([{Glyph,_}],_) -> Glyph; get_choice([{Glyph,Prob}|T],Ran) -> case (Ran < Prob) of true -> Glyph; false -> get_choice(T,Ran - Prob) end. ``` Output: ```txt [{aleph,0.2,0.200325}, {beth,0.16666666666666666,0.167108}, {gimel,0.14285714285714285,0.142246}, {daleth,0.125,0.124851}, {he,0.1111111111111111,0.111345}, {waw,0.1,0.099912}, {zayin,0.09090909090909091,0.091352}, {heth,0.06345598845598846,0.062861}] ``` ## ERRE ```ERRE PROGRAM PROB_CHOICE DIM ITEM\$[7],PROB[7],CNT[7] BEGIN ITEM\$[]=("aleph","beth","gimel","daleth","he","waw","zayin","heth") PROB[0]=1/5.0 PROB[1]=1/6.0 PROB[2]=1/7.0 PROB[3]=1/8.0 PROB[4]=1/9.0 PROB[5]=1/10.0 PROB[6]=1/11.0 PROB[7]=1759/27720 SUM=0 FOR I%=0 TO UBOUND(PROB,1) DO SUM=SUM+PROB[I%] END FOR IF ABS(SUM-1)>1E-6 THEN PRINT("Probabilities don't sum to 1") ELSE FOR TRIAL=1 TO 1E6 DO R=RND(1) P=0 FOR I%=0 TO UBOUND(PROB,1) DO P+=PROB[I%] IF R