September 2017 Update

This commit is contained in:
Ingy döt Net 2017-09-23 10:01:46 +02:00
parent bba7bfd280
commit ba8067c3b7
14570 changed files with 153136 additions and 63871 deletions

View file

@ -1,6 +1,6 @@
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).
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:<pre>
aleph 1/5.0
@ -11,3 +11,7 @@ he 1/9.0
waw 1/10.0
zayin 1/11.0
heth 1759/27720 # adjusted so that probabilities add to 1</pre>
;Related task:
* [[Random number generator (device)]]
<br><br>

View file

@ -1,20 +1,26 @@
import System.Random
import Data.List
import Control.Monad
import Control.Arrow
import System.Random (newStdGen, randomRs)
labels = ["aleph", "beth", "gimel", "daleth", "he", "waw", "zayin", "heth" ]
piv n = take n . (++ repeat ' ')
dataBinCounts :: [Float] -> [Float] -> [Int]
dataBinCounts thresholds range =
let sampleSize = length range
xs = ((-) sampleSize . length . flip filter range . (<)) <$> thresholds
in zipWith (-) (xs ++ [sampleSize]) (0 : xs)
main :: IO ()
main = do
g <- newStdGen
let rs,ps :: [Float]
rs = take 1000000 $ randomRs(0,1) g
ps = ap (++) (return. (1 -) .sum) $ map recip [5..11]
sps = scanl1 (+) ps
qs = (\xs -> map ((/1000000.0).fromIntegral.length. flip filter xs. (==))sps)
$ map (head . flip dropWhile sps . (>)) rs
putStrLn $ " expected actual"
mapM_ putStrLn $ zipWith3
(\l s c-> (piv 7 l) ++ (piv 13 $ show $ s)
++(piv 12 $ show $ c)) labels ps qs
let fractions = recip <$> [5 .. 11] :: [Float]
expected = fractions ++ [1 - sum fractions]
actual =
((/ 1000000.0) . fromIntegral) <$>
dataBinCounts (scanl1 (+) expected) (take 1000000 (randomRs (0, 1) g))
piv n = take n . (++ repeat ' ')
putStrLn " expected actual"
mapM_ putStrLn $
zipWith3
(\l s c -> piv 7 l ++ piv 13 (show s) ++ piv 12 (show c))
["aleph", "beth", "gimel", "daleth", "he", "waw", "zayin", "heth"]
expected
actual

View file

@ -0,0 +1,106 @@
(() => {
'use strict';
// GENERIC FUNCTIONS -----------------------------------------------------
// transpose :: [[a]] -> [[a]]
const transpose = xs =>
xs[0].map((_, iCol) => xs.map(row => row[iCol]));
// justifyLeft :: Int -> Char -> Text -> Text
const justifyLeft = (n, cFiller, strText) =>
n > strText.length ? (
(strText + cFiller.repeat(n))
.substr(0, n)
) : strText;
// 2 or more arguments
// curry :: Function -> Function
const curry = (f, ...args) => {
const go = xs => xs.length >= f.length ? (f.apply(null, xs)) :
function () {
return go(xs.concat([].slice.apply(arguments)));
};
return go([].slice.call(args, 1));
};
// zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
const zipWith = (f, xs, ys) => {
const ny = ys.length;
return (xs.length <= ny ? xs : xs.slice(0, ny))
.map((x, i) => f(x, ys[i]));
};
// subtract :: (Num a) => a -> a -> a
const subtract = (x, y) => y - x;
// scanl1 :: (a -> a -> a) -> [a] -> [a]
const scanl1 = (f, xs) =>
xs.length > 0 ? scanl(f, xs[0], xs.slice(1)) : [];
// scanl :: (b -> a -> b) -> b -> [a] -> [b]
const scanl = (f, startValue, xs) =>
xs.reduce((a, x) => {
const v = f(a.acc, x);
return {
acc: v,
scan: a.scan.concat(v)
};
}, {
acc: startValue,
scan: [startValue]
})
.scan;
// unwords :: [String] -> String
const unwords = xs => xs.join(' ');
// PROBABILISTIC CHOICE --------------------------------------------------
// samples :: Int -> Int -> [Float]
const samples = n =>
Array.from({
length: n
}, Math.random);
// thresholds :: Float
const thresholds = scanl1(
(a, b) => a + b, [5, 6, 7, 8, 9, 10, 11].map(x => 1 / x)
)
.concat(1);
// expected :: Float -> Float
const expected = limits =>
limits.map((x, i, xs) => i > 0 ? (x - xs[i - 1]) : x);
// dataBinCounts :: [Float] -> [Float] -> [Int]
const dataBinCounts = (thresholds, samples) => {
const
lng = samples.length,
xs = thresholds
.map(x => lng - samples.filter(v => v > x)
.length);
return zipWith(subtract, [0].concat(xs), xs.concat(lng));
};
// intSamples :: Integer
const intSamples = 1000000;
// aligned :: a -> String
const aligned = x => justifyLeft(12, ' ', isNaN(x) ? x : x.toFixed(7));
return transpose([
['', 'Aleph', 'Beit', 'Gimel', 'Dalet', 'He', 'Vav', 'Zayin', 'Chet']
.map(curry(justifyLeft)(7, ' ')),
['Expected'].concat(expected(thresholds))
.map(aligned),
['Observed'].concat(dataBinCounts(thresholds, samples(intSamples))
.map(x => x / intSamples))
.map(aligned)
])
.map(unwords)
.join('\n');
})();

View file

@ -0,0 +1,38 @@
// version 1.0.6
fun main(args: Array<String>) {
val letters = arrayOf("aleph", "beth", "gimel", "daleth", "he", "waw", "zayin", "heth")
val actual = IntArray(8)
val probs = doubleArrayOf(1/5.0, 1/6.0, 1/7.0, 1/8.0, 1/9.0, 1/10.0, 1/11.0, 0.0)
val cumProbs = DoubleArray(8)
cumProbs[0] = probs[0]
for (i in 1..6) cumProbs[i] = cumProbs[i - 1] + probs[i]
cumProbs[7] = 1.0
probs[7] = 1.0 - cumProbs[6]
val n = 1000000
(1..n).forEach {
val rand = Math.random()
when {
rand <= cumProbs[0] -> actual[0]++
rand <= cumProbs[1] -> actual[1]++
rand <= cumProbs[2] -> actual[2]++
rand <= cumProbs[3] -> actual[3]++
rand <= cumProbs[4] -> actual[4]++
rand <= cumProbs[5] -> actual[5]++
rand <= cumProbs[6] -> actual[6]++
else -> actual[7]++
}
}
var sumActual = 0.0
println("Letter\t Actual Expected")
println("------\t-------- --------")
for (i in 0..7) {
val generated = actual[i].toDouble() / n
println("${letters[i]}\t${String.format("%8.6f %8.6f", generated, probs[i])}")
sumActual += generated
}
println("\t-------- --------")
println("\t${"%8.6f".format(sumActual)} 1.000000")
}

View file

@ -1,47 +0,0 @@
import tables, math, strutils, times
const
num_trials = 1000000
precsn = 6
var start = cpuTime()
var probs = initTable[string,float](16)
probs.add("aleph", 1/5.0)
probs.add("beth", 1/6.0)
probs.add("gimel", 1/7.0)
probs.add("daleth", 1/8.0)
probs.add("he", 1/9.0)
probs.add("waw", 1/10.0)
probs.add("zayin", 1/11.0)
probs.add("heth", 1759/27720)
var samples = initTable[string,int](16)
for i, j in pairs(probs):
samples.add(i,0)
randomize()
for i in 1 .. num_trials:
var z = random(1.0)
for j,k in pairs(probs):
if z < probs[j]:
samples[j] = samples[j] + 1
break
else:
z = z - probs[j]
var s1, s2: float
echo("Item ","\t","Target ","\t","Results ","\t","Difference")
echo("==== ","\t","====== ","\t","======= ","\t","==========")
for i, j in pairs(probs):
s1 += samples[i]/num_trials*100.0
s2 += probs[i]*100.0
echo( i,
"\t", formatFloat(probs[i],ffDecimal,precsn),
"\t", formatFloat(samples[i]/num_trials,ffDecimal,precsn),
"\t", formatFloat(100.0*(1.0-(samples[i]/num_trials)/probs[i]),ffDecimal,precsn),"%")
echo("======","\t","======= ","\t","======== ")
echo("Total:","\t",formatFloat(s2,ffDecimal,2)," \t",formatFloat(s1,ffDecimal,2))
echo("\n",formatFloat(cpuTime()-start,ffDecimal,2)," secs")

View file

@ -0,0 +1,46 @@
$character = [PSCustomObject]@{
aleph = [PSCustomObject]@{Expected=1/5 ; Alpha="א"}
beth = [PSCustomObject]@{Expected=1/6 ; Alpha="ב"}
gimel = [PSCustomObject]@{Expected=1/7 ; Alpha="ג"}
daleth = [PSCustomObject]@{Expected=1/8 ; Alpha="ד"}
he = [PSCustomObject]@{Expected=1/9 ; Alpha="ה"}
waw = [PSCustomObject]@{Expected=1/10 ; Alpha="ו"}
zayin = [PSCustomObject]@{Expected=1/11 ; Alpha="ז"}
heth = [PSCustomObject]@{Expected=1759/27720; Alpha="ח"}
}
$sum = 0
$iterations = 1000000
$cumulative = [ordered]@{}
$randomly = [ordered]@{}
foreach ($name in $character.PSObject.Properties.Name)
{
$sum += $character.$name.Expected
$cumulative.$name = $sum
$randomly.$name = 0
}
for ($i = 0; $i -lt $iterations; $i++)
{
$random = Get-Random -Minimum 0.0 -Maximum 1.0
foreach ($name in $cumulative.Keys)
{
if ($random -le $cumulative.$name)
{
$randomly.$name++
break
}
}
}
foreach ($name in $character.PSObject.Properties.Name)
{
[PSCustomObject]@{
Name = $name
Expected = $character.$name.Expected
Actual = $randomly.$name / $iterations
Character = $character.$name.Alpha
}
}

View file

@ -1,32 +1,30 @@
/*REXX program displays results of probabilistic choices, gen random #s per probability.*/
parse arg trials digits seed . /*obtain the optional arguments from CL*/
parse arg trials digs seed . /*obtain the optional arguments from CL*/
if trials=='' | trials=="," then trials=1000000 /*Not specified? Then use the default.*/
if digits=='' | digits=="," then digits=15 /* " " " " " " */
if datatype(seed,'W') then call random ,,seed /*allows repeatability for RANDOM nums.*/
names= 'aleph beth gimel daleth he waw zayin heth totals'
cells=words(names) - 1; high=100000; s=0; !.=0
_=4
do n=1 for 7; _=_+1; prob.n=1/_; Hprob.n=prob.n*high; s=s+prob.n
end /*n*/ /* [↑] determine the probabilities. */
if digs=='' | digs=="," then digs=15 /* " " " " " " */
if datatype(seed, 'W') then call random ,,seed /*allows repeatability for RANDOM nums.*/
numeric digits digs /*use a specific number of decimal digs*/
names= 'aleph beth gimel daleth he waw zayin heth totals' /*names of cells.*/
#= words(names) - 1; s=0
HI=100000
do n=1 for #-1; prob.n=1 / (n+4); Hprob.n=prob.n * HI; s=s + prob.n
end /*n*/
!.=0
prob.#=1759/27720; !.9=trials; Hprob.#=prob.# * HI; s=s + prob.#
prob.9=s
do j=1 for trials; r=random(1, HI) /*generate X number of random numbers.*/
do k=1 for # /*for each cell, compute percentages. */
if r<=Hprob.k then !.k=!.k + 1 /* " " " range, bump the counter*/
end /*k*/
end /*j*/
@= '' /*@: a literal used for CENTER BIF pad*/
w=digs +6 /*W: display width for the percentages*/
d=4 + max( length(trials), length('count') ) /* [↓] display a formatted top header.*/
say center('name',15,@) center('count',d,@) center('target %',w,@) center('actual %',w,@)
prob.8=1759/27720; Hprob.8=prob.8*high; s=s+prob.8; prob.9=s; !.9=trials
do j=1 for trials; r=random(1, high) /*generate X number of random numbers.*/
do k=1 for cells /*for each cell, compute percentages. */
if r<=Hprob.k then !.k=!.k+1 /*for each range, bump the counter. */
end /*k*/
end /*j*/
w=digits+6; d=max(length(trials), length('count')) + 4
say centr('name',15) centr('count',d) centr('target %') centr('actual %')
/* [↑] display a formatted header line*/
do i=1 for cells+1 /*show for each of the cells and totals*/
say ' ' left(word(names,i) , 12),
right(!.i , d-2) " ",
left(format(prob.i *100, d), w-2),
left(format(!.i/trials*100, d), w-2)
if i==8 then say centr(,15) centr(,d) centr() centr()
end /*i*/
exit /*stick a fork in it, we are all done.*/
/*──────────────────────────────────────────────────────────────────────────────────────*/
centr: return center( arg(1), word(arg(2) w, 1), '')
do i=1 for #+1 /*display each of the cells and totals.*/
say ' ' left( word(names, i), 13) right(!.i, d-2) " ",
left( format( prob.i * 100, d), w-2),
left( format( !.i/trials * 100, d), w-2)
if i==# then say center(@,15,@) center(@,d,@) center(@,w,@) center(@,w,@)
end /*i*/ /*stick a fork in it, we are all done.*/

View file

@ -0,0 +1,22 @@
var names=T("aleph", "beth", "gimel", "daleth",
"he", "waw", "zayin", "heth");
var ptable=T(5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0).apply('/.fp(1.0));
ptable=ptable.append(1.0-ptable.sum(0.0)); // add last weight to sum to 1.0
var [const] N=ptable.len();
fcn ridx{ i:=0; s:=(0.0).random(1);
while((s-=ptable[i]) > 0) { i+=1 }
i
}
const M=0d1_000_000;
var r=(0).pump(N,List,T(Ref,0)); // list of references to int 0
(0).pump(M,Void,fcn{r[ridx()].inc()}); // 1,000,000 weighted random #s
r=r.apply("value").apply("toFloat"); // (reference to int)-->int-->float
println(" Name Count Ratio Expected");
foreach i in (N){
"%6s%7d %7.4f%% %7.4f%%".fmt(names[i], r[i], r[i]/M*100,
ptable[i]*100).println();
}