Verify distribution uniformity/Naive: Difference between revisions

m
(Add Factor implementation.)
m (→‎{{header|Wren}}: Minor tidy)
 
(48 intermediate revisions by 23 users not shown)
Line 1:
{{task|Probability and statistics}}
<small>This task is an adjunct to [[Seven-dice from Five-dice]].</small>
 
<small>This task is an adjunct to [[Seven-sided dice from five-sided dice]].</small>
 
 
;Task:
Create a function to check that the random integers returned from a small-integer generator function have uniform distribution.
 
 
The function should take as arguments:
Line 8 ⟶ 12:
* The number of times to call the integer generator.
* A 'delta' value of some sort that indicates how close to a flat distribution is close enough.
 
 
The function should produce:
Line 13 ⟶ 18:
* An 'error' if the distribution is not flat enough.
 
 
Show the distribution checker working when the produced distribution is flat enough and when it is not. (Use a generator from [[Seven-dice from Five-dice]]).
Show the distribution checker working when the produced distribution is flat enough and when it is not. (Use a generator from [[Seven-sided dice from five-sided dice]]).
 
 
See also:
*[[Verify distribution uniformity/Chi-squared test]]
<br><br>
 
=={{header|11l}}==
{{trans|Python}}
 
<syntaxhighlight lang="11l">F dice5()
R random:(1..5)
 
F distcheck(func, repeats, delta)
V bin = DefaultDict[Int, Int]()
L 1..repeats
bin[func()]++
V target = repeats I/ bin.len
V deltacount = Int(delta / 100.0 * target)
assert(all(bin.values().map(count -> abs(@target - count) < @deltacount)), ‘Bin distribution skewed from #. +/- #.: #.’.format(target, deltacount, sorted(bin.items()).map((key, count) -> (key, @target - count))))
print(bin)
 
distcheck(dice5, 1000000, 1)</syntaxhighlight>
 
{{out}}
<pre>
DefaultDict([1 = 199586, 2 = 200094, 3 = 198933, 4 = 200824, 5 = 200563])
</pre>
 
=={{header|Ada}}==
 
<langsyntaxhighlight Adalang="ada">with Ada.Numerics.Discrete_Random, Ada.Text_IO;
 
procedure Naive_Random is
Line 70 ⟶ 100:
 
Ada.Text_IO.Put_Line("Test Passed? (" & Boolean'Image(OK) & ")");
end Naive_Random;</langsyntaxhighlight>
 
Sample run 1 (all buckets good):<pre>7
Line 101 ⟶ 131:
 
=={{header|AutoHotkey}}==
<langsyntaxhighlight AutoHotkeylang="autohotkey">MsgBox, % DistCheck("dice7",10000,3)
 
DistCheck(function, repetitions, delta)
Line 123 ⟶ 153:
}
Return, text
}</langsyntaxhighlight>
<pre>Distribution check:
 
Line 140 ⟶ 170:
=={{header|BBC BASIC}}==
{{works with|BBC BASIC for Windows}}
<langsyntaxhighlight lang="bbcbasic"> MAXRND = 7
FOR r% = 2 TO 5
check% = FNdistcheck(FNdice5, 10^r%, 0.05)
Line 166 ⟶ 196:
= s%
DEF FNdice5 = RND(5)</langsyntaxhighlight>
Output:
<pre>
Line 176 ⟶ 206:
 
=={{header|C}}==
<langsyntaxhighlight lang="c">#include <stdlib.h>
#include <stdio.h>
#include <math.h>
Line 221 ⟶ 251:
 
return 0;
}</langsyntaxhighlight>output<pre>
Count = 10: bin 1 out of range: 1 (-30% vs 3%), NOT flat
Count = 100: bin 1 out of range: 11 (-23% vs 3%), NOT flat
Line 229 ⟶ 259:
Count = 1000000: flat
</pre>
 
=={{header|C#}}==
{{trans|Java}}
<syntaxhighlight lang="C#">
using System;
using System.Collections.Generic;
using System.Linq;
 
public class Test
{
static void DistCheck(Func<int> func, int nRepeats, double delta)
{
var counts = new Dictionary<int, int>();
 
for (int i = 0; i < nRepeats; i++)
{
int result = func();
if (counts.ContainsKey(result))
counts[result]++;
else
counts[result] = 1;
}
 
double target = nRepeats / (double)counts.Count;
int deltaCount = (int)(delta / 100.0 * target);
 
foreach (var kvp in counts)
{
if (Math.Abs(target - kvp.Value) >= deltaCount)
Console.WriteLine("distribution potentially skewed for '{0}': '{1}'", kvp.Key, kvp.Value);
}
 
foreach (var key in counts.Keys.OrderBy(k => k))
{
Console.WriteLine("{0} {1}", key, counts[key]);
}
}
 
public static void Main(string[] args)
{
DistCheck(() => new Random().Next(1, 6), 1_000_000, 1);
}
}
</syntaxhighlight>
{{out}}
<pre>
1 200274
2 199430
3 199418
4 200473
5 200405
 
</pre>
 
 
=={{header|C++}}==
<langsyntaxhighlight lang="cpp">#include <map>
#include <iostream>
#include <cmath>
Line 261 ⟶ 345:
 
return good;
}</langsyntaxhighlight>
 
=={{header|Clojure}}==
The code could be shortened if the verify function did the output itself, but the "Clojure way" is to have functions, whenever possible, avoid side effects (like printing) and just return a result. Then the "application-level" code uses doseq and println to display the output to the user. The built-in (rand-int) function is used for all three runs of the verify function, but first with small N to simulate experimental error in a small sample size, then with larger N to show it working properly on large N.
<langsyntaxhighlight lang="clojure">(defn verify [rand n & [delta]]
(let [rands (frequencies (repeatedly n rand))
avg (/ (reduce + (map val rands)) (count rands))
Line 276 ⟶ 360:
[num count okay?] (verify #(rand-int 7) n)]
(println "Saw" num count "times:"
(if okay? "that's" " not") "acceptable"))</langsyntaxhighlight>
 
<pre>Saw 1 13 times: that's acceptable
Line 302 ⟶ 386:
=={{header|Common Lisp}}==
{{trans|OCaml}}
<langsyntaxhighlight lang="lisp">(defun check-distribution (function n &optional (delta 1.0))
(let ((bins (make-hash-table)))
(loop repeat n do (incf (gethash (funcall function) bins 0)))
Line 310 ⟶ 394:
do (format t "~&Distribution potentially skewed for ~w:~
expected around ~w got ~w." key target value)
finally (return bins))))</langsyntaxhighlight>
 
<pre>> (check-distribution 'd7 1000)
Line 325 ⟶ 409:
 
=={{header|D}}==
<langsyntaxhighlight lang="d">import std.stdio, std.string, std.math, std.algorithm, std.traits;
 
/**
Line 355 ⟶ 439:
distCheck(() => uniform(1, 6), 1_000_000, 1);
}
}</langsyntaxhighlight>
If compiled with -version=verify_distribution_uniformity_naive_main:
{{out}}
Line 362 ⟶ 446:
4 200016
5 200424</pre>
 
=={{header|Elixir}}==
{{trans|Erlang}}
<syntaxhighlight lang="elixir">defmodule VerifyDistribution do
def naive( generator, times, delta_percent ) do
dict = Enum.reduce( List.duplicate(generator, times), Map.new, &update_counter/2 )
values = Map.values(dict)
average = Enum.sum( values ) / map_size( dict )
delta = average * (delta_percent / 100)
fun = fn {_key, value} -> abs(value - average) > delta end
too_large_dict = Enum.filter( dict, fun )
return( length(too_large_dict), too_large_dict, average, delta_percent )
end
def return( 0, _too_large_dict, _average, _delta ), do: :ok
def return( _n, too_large_dict, average, delta ) do
{:error, {too_large_dict, :failed_expected_average, average, 'with_delta_%', delta}}
end
def update_counter( fun, dict ), do: Map.update( dict, fun.(), 1, &(&1+1) )
end
 
fun = fn -> Dice.dice7 end
IO.inspect VerifyDistribution.naive( fun, 100000, 3 )
IO.inspect VerifyDistribution.naive( fun, 100, 3 )</syntaxhighlight>
 
{{out}}
<pre>
:ok
{:error,
{[{1, 16}, {2, 10}, {4, 15}, {5, 8}, {6, 20}, {7, 17}],
:failed_expected_average, 14.285714285714286, 'with_delta_%', 3}}
</pre>
 
=={{header|Erlang}}==
<syntaxhighlight lang="erlang">
<lang Erlang>
-module( verify_distribution_uniformity ).
 
Line 385 ⟶ 502:
 
update_counter( Fun, Dict ) -> dict:update_counter( Fun(), 1, Dict ).
</syntaxhighlight>
</lang>
 
{{out}}
Line 403 ⟶ 520:
Following the task verbatim.
 
<syntaxhighlight lang="text">
>function checkrandom (frand$, n:index, delta:positive real) ...
$ v=zeros(1,n);
Line 419 ⟶ 536:
>checkrandom("wrongdice",1000000,1)
0
</syntaxhighlight>
</lang>
 
Checking the dice7 from dice5 generator.
 
<syntaxhighlight lang="text">
>function dice5 () := intrandom(1,1,5);
>function dice7 () ...
Line 433 ⟶ 550:
>checkrandom("dice7",1000000,1)
1
</syntaxhighlight>
</lang>
 
Faster implementation with the matrix language.
 
<syntaxhighlight lang="text">
>function dice5(n) := intrandom(1,n,5)-1;
>function dice7(n) ...
Line 456 ⟶ 573:
>checkrandom(wrongdice(1000000))
0
</syntaxhighlight>
</lang>
 
=={{header|Factor}}==
<langsyntaxhighlight lang="factor">USING: kernel random mathsequences math.functionsassocs math.vectorslocals sequences localssorting prettyprint ;
math math.functions math.statistics math.vectors math.ranges ;
IN: dice7
IN: rosetta-code.dice7
 
! Output a random numberinteger 1..5.
: dice5 ( -- x )
5 [1,b] random
random-unit 5 * floor 1 + >integer
;
 
! Output a random numberinteger 1..7 using dice5 as randomness source.
: dice7 ( -- x )
0 [ dup 21 < ] [ drop dice5 5 * dice5 + 6 - ] do until
7 rem 1 + >integer
;
 
! Roll dicethe usingdie theby passedcalling wordthe quotation the given number of times and produce anreturn
! an array with roll results.
! Sample call: \1000 [ dice7 1000] roll
: roll ( wordtimes quot: ( -- x ) times -- array )
iota [ drop dup executecall( -- x ) ] mapcurry replicate
nip
;
 
Line 486 ⟶ 603:
! there is the number of ones in the input array, in the second position
! of the result there is the number of twos in the input array, etc.
: count-diceXdice-outcomes ( array X array -- array )
histogram
iota [ 1 + dupd [ = ] curry count ] map
swap [1,b] [ over [ 0 or ] change-at ] each
swap length
sort-keys values
over sum
assert=
;
 
! Verify distribution uniformity/Naive. Delta is the acceptable deviation
! from the ideal number of items in each bucket, expressed as a fraction of
! the total count. Sides is the number of die sides. RndDie-func is a word that
! produces a random number on stack in the range [1..sides], times is the
! number of times to call it.
! Sample call: 0.02 7 \[ dice7 ] 100000 verify
:: verify ( delta sides rnddie-func: ( -- random ) times -- )
sides
rnd-func times roll
times die-func roll
sides count-diceX-outcomes
count-dice-outcomes
dup .
times sides / :> ideal-count
ideal-count v-n vabs
times v/n
delta [ < ] curry mapall?
vall? [ "Random enough" . ] [ "Not random enough" . ] if
;
 
Line 514 ⟶ 631:
: verify-all ( -- )
{ 1 10 100 1000 10000 100000 1000000 }
[| times | 0.02 7 \[ dice7 ] times verify ] each
;</langsyntaxhighlight>
 
Output:
<pre>USE: rosetta-code.dice7 verify-all
{ 0 1 0 0 1 0 0 0 }
"Not random enough"
{ 30 2 3 1 1 1 1 02 }
"Not random enough"
{ 1117 12 1815 2211 1213 13 1219 }
"Not random enough"
{ 151140 130 172141 138148 145143 141155 123143 }
"Not random enough"
{ 1404 1446 1371 1460 1431 1440 1448 }
"Random enough"
{ 143111457 141391373 143881427 143461433 141501443 144051382 142611485 }
"Random enough"
{ 14225 14320 14216 14326 14415 14084 14414 }
{ 142877 143514 142441 142380 143141 143203 142444 }
"Random enough"
{ 142599 141910 142524 143029 143353 142696 143889 }
"Random enough"</pre>
 
=={{header|Forth}}==
requires Forth200x locals
<syntaxhighlight lang="forth">: .bounds ( u1 u2 -- ) ." lower bound = " . ." upper bound = " 1- . cr ;
: init-bins ( n -- addr )
cells dup allocate throw tuck swap erase ;
: expected ( u1 cnt -- u2 ) over 2/ + swap / ;
: calc-limits ( n cnt pct -- low high )
>r expected r> over 100 */ 2dup + 1+ >r - r> ;
: make-histogram ( bins xt cnt -- )
0 ?do 2dup execute 1- cells + 1 swap +! loop 2drop ;
: valid-bin? ( addr n low high -- f )
2>r cells + @ dup . 2r> within ;
 
: check-distribution {: xt cnt n pct -- f :}
\ assumes xt generates numbers from 1 to n
n init-bins {: bins :}
n cnt pct calc-limits {: low high :}
high low .bounds
bins xt cnt make-histogram
true \ result flag
n 0 ?do
i 1+ . ." : " bins i low high valid-bin?
dup 0= if ." not " then ." ok" cr
and
loop
bins free throw ;</syntaxhighlight>
{{output}}
<pre>cr ' d7 1000000 7 1 check-distribution .
lower bound = 141429 upper bound = 144285
1 : 143241 ok
2 : 142397 ok
3 : 143522 ok
4 : 142909 ok
5 : 142001 ok
6 : 142844 ok
7 : 143086 ok
-1
 
cr ' d7 10000 7 1 check-distribution .
lower bound = 1415 upper bound = 1443
1 : 1431 ok
2 : 1426 ok
3 : 1413 not ok
4 : 1427 ok
5 : 1437 ok
6 : 1450 not ok
7 : 1416 ok
0</pre>
 
=={{header|Fortran}}==
{{works with|Fortran|95 and later}}
<langsyntaxhighlight lang="fortran">subroutine distcheck(randgen, n, delta)
 
interface
Line 581 ⟶ 747:
deallocate(buckets)
end subroutine</langsyntaxhighlight>
 
 
=={{header|FreeBASIC}}==
{{trans|Liberty BASIC}}
<syntaxhighlight lang="freebasic">
Randomize Timer
Function dice5() As Integer
Return Int(Rnd * 5) + 1
End Function
 
Function dice7() As Integer
Dim As Integer temp
Do
temp = dice5() * 5 + dice5() -6
Loop Until temp < 21
Return (temp Mod 7) +1
End Function
 
Function distCheck(n As Ulongint, delta As Double) As Ulongint
 
Dim As Ulongint a(n)
Dim As Ulongint maxBucket = 0
Dim As Ulongint minBucket = 1000000
For i As Ulongint = 1 To n
a(i) = dice5()
If a(i) > maxBucket Then maxBucket = a(i)
If a(i) < minBucket Then minBucket = a(i)
Next i
Dim As Ulongint nBuckets = maxBucket + 1
Dim As Ulongint buckets(maxBucket)
For i As Ulongint = 1 To n
buckets(a(i)) += 1
Next i
'check buckets
Dim As Ulongint expected = n / (maxBucket-minBucket+1)
Dim As Ulongint minVal = Int(expected*(1-delta))
Dim As Ulongint maxVal = Int(expected*(1+delta))
expected = Int(expected)
Print "minVal", "Expected", "maxVal"
Print minVal, expected, maxVal
Print "Bucket", "Counter", "pass/fail"
distCheck = true
For i As Ulongint = minBucket To maxBucket
Print i, buckets(i), Iif((minVal > buckets(i)) Or (buckets(i) > maxVal),"fail","")
If (minVal > buckets(i)) Or (buckets(i) > maxVal) Then Return false
Next i
End Function
 
Dim Shared As Ulongint n = 1000
Print "Testing ";n;" times"
If Not(distCheck(n, 0.05)) Then Print "Test failed" Else Print "Test passed"
Print
 
n = 10000
Print "Testing ";n;" times"
If Not(distCheck(n, 0.05)) Then Print "Test failed" Else Print "Test passed"
Print
 
n = 50000
Print "Testing ";n;" times"
If Not(distCheck(n, 0.05)) Then Print "Test failed" Else Print "Test passed"
Print
Sleep
</syntaxhighlight>
{{out}}
<pre>
Igual que la entrada de Liberty BASIC.
</pre>
 
 
=={{header|Go}}==
<langsyntaxhighlight lang="go">package main
 
import (
Line 639 ⟶ 875:
max, flatEnough = distCheck(dice7, 7, calls, 500)
fmt.Println("Max delta:", max, "Flat enough:", flatEnough)
}</langsyntaxhighlight>
Output:
<pre>
Line 647 ⟶ 883:
 
=={{header|Haskell}}==
<langsyntaxhighlight lang="haskell">import System.Random
import Data.List
import Control.Monad
Line 659 ⟶ 895:
ul = round $ (100 + fromIntegral d)/100 * avg
ll = round $ (100 - fromIntegral d)/100 * avg
return $ map (head &&& (id &&& liftM2 (&&) (>ll)(<ul)).length) group</langsyntaxhighlight>
Example:
<langsyntaxhighlight lang="haskell">*Main> mapM_ print .sort =<< distribCheck (randomRIO(1,6)) 100000 3
(1,(16911,True))
(2,(16599,True))
Line 667 ⟶ 903:
(4,(16624,True))
(5,(16526,True))
(6,(16670,True))</langsyntaxhighlight>
 
=={{header|Hy}}==
 
<langsyntaxhighlight lang="lisp">(import [collections [Counter]])
(import [random [randint]])
 
Line 682 ⟶ 918:
(all (list-comp
(<= (- target delta) (/ n repeats) (+ target delta))
[n (.values bins)])))</langsyntaxhighlight>
 
Examples of use:
 
<langsyntaxhighlight lang="lisp">(for [f [
(fn [] (randint 1 10))
(fn [] (if (randint 0 1) (randint 1 9) (randint 1 10)))]]
(print (uniform? f 5000 .02)))</langsyntaxhighlight>
 
=={{header|Icon}} and {{header|Unicon}}==
This example assumes the random number generator is passed to <code>verify_uniform</code> as a co-expression. The co-expression <code>rnd</code> is prompted for its next value using <code>@rnd</code>. The co-expression is created using <code>create (|?10)</code> where the vertical bar means generate an infinite sequence of what is to its right (in this case, <code>?10</code> generates a random integer in the range [1,10]).
<langsyntaxhighlight Iconlang="icon"># rnd : a co-expression, which will generate the random numbers
# n : the number of numbers to test
# delta: tolerance in non-uniformity
Line 723 ⟶ 959:
then write ("uniform")
else write ("skewed")
end</langsyntaxhighlight>
Output:
<pre>
Line 754 ⟶ 990:
 
The ''delta'' is given as an optional left argument (<code>x</code>), defaulting to 5%. The right argument (<code>y</code>) is any valid argument to the distribution generating verb.
<langsyntaxhighlight lang="j">checkUniform=: adverb define
0.05 u checkUniform y
:
Line 765 ⟶ 1,001:
errmsg assert (delta * expected) > | expected - {:"1 freqtable
freqtable
)</langsyntaxhighlight>
It is possible to use tacit expressions within an explicit definition enabling a more functional and concise style:
<langsyntaxhighlight lang="j">checkUniformT=: adverb define
0.05 u checkUniformT y
:
Line 774 ⟶ 1,010:
errmsg assert ((n % #) (x&*@[ > |@:-) {:"1) freqtable
freqtable
)</langsyntaxhighlight>
Show usage using <code>rollD7t</code> given in [[Seven-dice from Five-dice#J|Seven-dice from Five-dice]]:
<langsyntaxhighlight lang="j"> 0.05 rollD7t checkUniform 1e5
1 14082
2 14337
Line 786 ⟶ 1,022:
0.05 rollD7t checkUniform 1e2
|Distribution is potentially skewed: assert
| errmsg assert(delta*expected)>|expected-{:"1 freqtable</langsyntaxhighlight>
 
=={{header|Java}}==
{{trans|D}}
{{works with|Java|8}}
<syntaxhighlight lang="java">import static java.lang.Math.abs;
import java.util.*;
import java.util.function.IntSupplier;
 
public class Test {
 
static void distCheck(IntSupplier f, int nRepeats, double delta) {
Map<Integer, Integer> counts = new HashMap<>();
 
for (int i = 0; i < nRepeats; i++)
counts.compute(f.getAsInt(), (k, v) -> v == null ? 1 : v + 1);
 
double target = nRepeats / (double) counts.size();
int deltaCount = (int) (delta / 100.0 * target);
 
counts.forEach((k, v) -> {
if (abs(target - v) >= deltaCount)
System.out.printf("distribution potentially skewed "
+ "for '%s': '%d'%n", k, v);
});
 
counts.keySet().stream().sorted().forEach(k
-> System.out.printf("%d %d%n", k, counts.get(k)));
}
 
public static void main(String[] a) {
distCheck(() -> (int) (Math.random() * 5) + 1, 1_000_000, 1);
}
}</syntaxhighlight>
<pre>1 200439
2 201016
3 199406
4 199869
5 199270</pre>
 
=={{header|JavaScript}}==
{{trans|Tcl}}
<langsyntaxhighlight lang="javascript">function distcheck(random_func, times, opts) {
if (opts === undefined) opts = {}
opts['delta'] = opts['delta'] || 2;
Line 829 ⟶ 1,103:
} catch (e) {
print(e);
}</langsyntaxhighlight>
Output:
<pre>0 9945
Line 844 ⟶ 1,118:
distribution potentially skewed for 0: expected result around 50000, got 95040</pre>
 
=={{header|MathematicaJulia}}==
<syntaxhighlight lang="julia">using Printf
<lang Mathematica>SetAttributes[CheckDistribution, HoldFirst]
 
function distcheck(f::Function, rep::Int=10000, Δ::Int=3)
smpl = f(rep)
counts = Dict(k => count(smpl .== k) for k in unique(smpl))
expected = rep / length(counts)
lbound = expected * (1 - 0.01Δ)
ubound = expected * (1 + 0.01Δ)
noobs = count(x -> !(lbound ≤ x ≤ ubound), values(counts))
if noobs > 0 warn(@sprintf "%2.4f%% values out of bounds" noobs / rep) end
return counts
end
 
# Dice5 check
distcheck(x -> rand(1:5, x))
# Dice7 check
distcheck(dice7)</syntaxhighlight>
 
=={{header|Kotlin}}==
<syntaxhighlight lang="scala">// version 1.1.3
 
import java.util.Random
 
val r = Random()
 
fun dice5() = 1 + r.nextInt(5)
 
fun checkDist(gen: () -> Int, nRepeats: Int, tolerance: Double = 0.5) {
val occurs = mutableMapOf<Int, Int>()
for (i in 1..nRepeats) {
val d = gen()
if (occurs.containsKey(d))
occurs[d] = occurs[d]!! + 1
else
occurs.put(d, 1)
}
val expected = (nRepeats.toDouble()/ occurs.size).toInt()
val maxError = (expected * tolerance / 100.0).toInt()
println("Repetitions = $nRepeats, Expected = $expected")
println("Tolerance = $tolerance%, Max Error = $maxError\n")
println("Integer Occurrences Error Acceptable")
val f = " %d %5d %5d %s"
var allAcceptable = true
for ((k,v) in occurs.toSortedMap()) {
val error = Math.abs(v - expected)
val acceptable = if (error <= maxError) "Yes" else "No"
if (acceptable == "No") allAcceptable = false
println(f.format(k, v, error, acceptable))
}
println("\nAcceptable overall: ${if (allAcceptable) "Yes" else "No"}")
}
 
fun main(args: Array<String>) {
checkDist(::dice5, 1_000_000)
println()
checkDist(::dice5, 100_000)
}</syntaxhighlight>
 
Sample output:
<pre>
Repetitions = 1000000, Expected = 200000
Tolerance = 0.5%, Max Error = 1000
 
Integer Occurrences Error Acceptable
1 200074 74 Yes
2 200497 497 Yes
3 199295 705 Yes
4 199822 178 Yes
5 200312 312 Yes
 
Acceptable overall: Yes
 
Repetitions = 100000, Expected = 20000
Tolerance = 0.5%, Max Error = 100
 
Integer Occurrences Error Acceptable
1 20265 265 No
2 20229 229 No
3 19836 164 No
4 19931 69 Yes
5 19739 261 No
 
Acceptable overall: No
</pre>
 
=={{header|Liberty BASIC}}==
LB cannot pass user-defined function by name, so we use predefined function name - GENERATOR
<syntaxhighlight lang="lb">
n=1000
print "Testing ";n;" times"
if not(check(n, 0.05)) then print "Test failed" else print "Test passed"
print
 
n=10000
print "Testing ";n;" times"
if not(check(n, 0.05)) then print "Test failed" else print "Test passed"
print
 
n=50000
print "Testing ";n;" times"
if not(check(n, 0.05)) then print "Test failed" else print "Test passed"
print
 
end
 
function check(n, delta)
'fill randoms
dim a(n)
maxBucket=0
minBucket=1e10
for i = 1 to n
a(i) = GENERATOR()
if a(i)>maxBucket then maxBucket=a(i)
if a(i)<minBucket then minBucket=a(i)
next
'fill buckets
nBuckets = maxBucket+1 'from 0
dim buckets(maxBucket)
for i = 1 to n
buckets(a(i)) = buckets(a(i))+1
next
'check buckets
expected=n/(maxBucket-minBucket+1)
minVal=int(expected*(1-delta))
maxVal=int(expected*(1+delta))
expected=int(expected)
print "minVal", "Expected", "maxVal"
print minVal, expected, maxVal
print "Bucket", "Counter", "pass/fail"
check = 1
for i = minBucket to maxBucket
print i, buckets(i), _
iif$((minVal > buckets(i)) OR (buckets(i) > maxVal) ,"fail","")
if (minVal > buckets(i)) OR (buckets(i) > maxVal) then check = 0
next
end function
 
function iif$(test, valYes$, valNo$)
iif$ = valNo$
if test then iif$ = valYes$
end function
 
function GENERATOR()
'GENERATOR = int(rnd(0)*10) '0..9
GENERATOR = 1+int(rnd(0)*5) '1..5: dice5
end function
</syntaxhighlight>
{{Out}}
<pre>
Testing 1000 times
minVal Expected maxVal
190 200 210
Bucket Counter pass/fail
1 213 fail
2 204
3 192
4 188 fail
5 203
Test failed
 
Testing 10000 times
minVal Expected maxVal
1900 2000 2100
Bucket Counter pass/fail
1 2041
2 1952
3 1975
4 2026
5 2006
Test passed
 
Testing 50000 times
minVal Expected maxVal
9500 10000 10500
Bucket Counter pass/fail
1 10012
2 10207
3 10009
4 9911
5 9861
Test passed
</pre>
 
=={{header|Mathematica}}/{{header|Wolfram Language}}==
<syntaxhighlight lang="mathematica">SetAttributes[CheckDistribution, HoldFirst]
CheckDistribution[function_,number_,delta_] :=(Print["Expected: ", N[number/7], ", Generated :",
Transpose[Tally[Table[function, {number}]]][[2]] // Sort]; If[(Max[#]-Min[#])&
[Transpose[Tally[Table[function, {number}]]][[2]]] < delta*number/700, "Flat", "Skewed"])</langsyntaxhighlight>
 
Example usage:
Line 860 ⟶ 1,318:
->Expected: 14285.7, Generated :{14182,14186,14240,14242,14319,14407,14424}
->"Flat"</pre>
 
=={{header|Nim}}==
<syntaxhighlight lang="nim">import tables
 
 
proc checkDist(f: proc(): int; repeat: Positive; tolerance: float) =
 
var counts: CountTable[int]
for _ in 1..repeat:
counts.inc f()
 
let expected = (repeat / counts.len).toInt # Rounded to nearest.
let allowedDelta = (expected.toFloat * tolerance / 100).toInt
var maxDelta = 0
for val, count in counts.pairs:
let d = abs(count - expected)
if d > maxDelta: maxDelta = d
let status = if maxDelta <= allowedDelta: "passed" else: "failed"
echo "Checking ", repeat, " values with a tolerance of ", tolerance, "%."
echo "Random generator ", status, " the uniformity test."
echo "Max delta encountered = ", maxDelta, " Allowed delta = ", allowedDelta
 
 
when isMainModule:
import random
randomize()
proc rand5(): int = rand(1..5)
checkDist(rand5, 1_000_000, 0.5)
</syntaxhighlight>
 
{{out}}
<pre>Checking 1000000 values with a tolerance of 0.5%.
Random generator passed the uniformity test.
Max delta encountered = 659 Allowed delta = 1000</pre>
 
=={{header|OCaml}}==
<langsyntaxhighlight lang="ocaml">let distcheck fn n ?(delta=1.0) () =
let h = Hashtbl.create 5 in
for i = 1 to n do
Line 880 ⟶ 1,373:
key target value)
) h;
;;</langsyntaxhighlight>
 
=={{header|PARI/GP}}==
This tests the purportedly random 7-sided die with a slightly biased 1000-sided die.
<langsyntaxhighlight lang="parigp">dice5()=random(5)+1;
dice7()={
Line 913 ⟶ 1,406:
 
test(dice7, 10^5)
test(()->if(random(1000),random(1000),1), 10^5)</langsyntaxhighlight>
Output:
<pre>Flat with significance 0.2931867820813680387842134664085280183
Line 919 ⟶ 1,412:
### user error: Not flat enough, significance only 5.391077606003910233 E-3500006</pre>
 
=={{header|Perl 6}}==
Testing two 'types' of 7-sided dice. Both appear to be fair.
Since the tested function is rolls of a 7 sided die, the test numbers are magnitudes of 10<sup>x</sup> bumped up to the closest multiple of 7. This reduces spurious error from there not being an integer expected value.
{{trans|Raku}}
<lang perl6>my $d7 = 1..7;
<syntaxhighlight lang="perl">sub roll7 { $d7.roll1+int rand(7) };
sub roll5 { 1+int rand(5) }
sub roll7_5 {
while(1) {
my $d7 = (5*&roll5 + &roll5 - 6) % 8;
return $d7 if $d7;
}
}
 
my $threshold = 35;
 
print dist( $_, $threshold, \&roll7 ) for <1001 1000006>;
for 14, 105, 1001, 10003, 100002, 1000006 -> $n
{print dist( $n_, $threshold, \&roll7roll7_5 ) }for <1001 1000006>;
 
sub dist {
 
sub dist my( $n is copy, $threshold, &$producer) )= {@_;
my @dist;
my $result;
my $expect = $n / 7;
say$result .= sprintf "Expect%10d expected\tn", $expect.fmt("%.3f");
 
loopfor ($_ = $n; $n; --1..$n) { @dist[&$producer()]++; }
 
for @dist.kv ->my $i, $v is copy(1..7) {
nextmy unless$v = @dist[$i];
$v //= 0;
my $pct = ($v - $expect)/$expect*100;
printf$result .= sprintf "%d\t %d\t8d %+6.2f1f%% %s\n", $i, $v, $pct, (abs($pct) > $threshold ? ' - skewed' : '');
($pct.abs > $threshold ?? '- skewed' !! '');
}
sayreturn ''$result . "\n";
}</langsyntaxhighlight>
{{out}}
Sample output:
<pre> 143 expected
1 144 0.7%
Expect 2.000
12 137 2 +0-4.002%
23 3 121 +50-15.004% - skewed
34 163 2 14.0% - +0.00%skewed
45 150 2 +04.009%
56 138 3 +50-3.005% - skewed
67 148 0 -1003.005% - skewed
7 2 +0.00%
 
142858 expected
Expect 15.000
1 142332 15 +-0.004%
2 142648 17 +13-0.331% - skewed
3 143615 13 -130.335% - skewed
4 142305 16 +6-0.674% - skewed
5 14 142703 -60.671% - skewed
6 142821 16 +6-0.670% - skewed
7 143582 14 -60.675% - skewed
 
Expect 143.000 expected
1 149 134 -64.292% - skewed
2 159 142 11.2% - -0.70%skewed
3 154 141 -17.407% - skewed
4 137 130 -49.201% - skewed
5 143 142 -0.700%
6 138 170 +18-3.885% - skewed
7 135 128 -10.5.59% - skewed
 
142858 expected
Expect 1429.000
1 1396 142574 -0.2.31%
2 143043 1468 +20.731%
3 1405 142446 -10.683%
4 143325 1442 +0.913%
5 142949 1453 +0.1.68%
6 142990 1417 -0.841%
7 1422 142679 -0.491%</pre>
 
=={{header|Phix}}==
Expect 14286.000
<!--<syntaxhighlight lang="phix">(phixonline)-->
1 14222 -0.45%
<span style="color: #008080;">with</span> <span style="color: #008080;">javascript_semantics</span>
2 14320 +0.24%
<span style="color: #008080;">function</span> <span style="color: #000000;">check</span><span style="color: #0000FF;">(</span><span style="color: #004080;">integer</span> <span style="color: #000000;">fid</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">range</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">iterations</span><span style="color: #0000FF;">,</span> <span style="color: #004080;">atom</span> <span style="color: #000000;">delta</span><span style="color: #0000FF;">)</span>
3 14326 +0.28%
<span style="color: #000080;font-style:italic;">--
4 14425 +0.97%
-- fid: routine_id of function that yields integer 1..range
5 14140 -1.02%
-- range: the maximum value that is returned from fid
6 14275 -0.08%
-- iterations: number of iterations to test
7 14294 +0.06%
-- delta: variance, for example 0.005 means 0.5%
 
--
Expect 142858.000
-- returns -1/0/1 for impossible/not flat/flat.
1 142510 -0.24%
--</span>
2 142436 -0.30%
<span style="color: #004080;">atom</span> <span style="color: #000000;">av</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">iterations</span><span style="color: #0000FF;">/</span><span style="color: #000000;">range</span> <span style="color: #000080;font-style:italic;">-- average/expected value</span>
3 142438 -0.29%
4 143152 +0.21%
<span style="color: #008080;">if</span> <span style="color: #7060A8;">floor</span><span style="color: #0000FF;">(</span><span style="color: #000000;">av</span><span style="color: #0000FF;">)<</span><span style="color: #000000;">av</span><span style="color: #0000FF;">-</span><span style="color: #000000;">delta</span><span style="color: #0000FF;">*</span><span style="color: #000000;">av</span>
5 142905 +0.03%
<span style="color: #008080;">or</span> <span style="color: #7060A8;">ceil</span><span style="color: #0000FF;">(</span><span style="color: #000000;">av</span><span style="color: #0000FF;">)></span><span style="color: #000000;">av</span><span style="color: #0000FF;">+</span><span style="color: #000000;">delta</span><span style="color: #0000FF;">*</span><span style="color: #000000;">av</span> <span style="color: #008080;">then</span>
6 143232 +0.26%
<span style="color: #008080;">return</span> <span style="color: #0000FF;">-</span><span style="color: #000000;">1</span> <span style="color: #000080;font-style:italic;">-- impossible</span>
7 143333 +0.33%
<span style="color: #008080;">end</span> <span style="color: #008080;">if</span>
<span style="color: #004080;">sequence</span> <span style="color: #000000;">counts</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">repeat</span><span style="color: #0000FF;">(</span><span style="color: #000000;">0</span><span style="color: #0000FF;">,</span><span style="color: #000000;">range</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">i</span><span style="color: #0000FF;">=</span><span style="color: #000000;">1</span> <span style="color: #008080;">to</span> <span style="color: #000000;">iterations</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">cdx</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">fid</span><span style="color: #0000FF;">()</span>
<span style="color: #000000;">counts</span><span style="color: #0000FF;">[</span><span style="color: #000000;">cdx</span><span style="color: #0000FF;">]</span> <span style="color: #0000FF;">+=</span> <span style="color: #000000;">1</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<span style="color: #004080;">atom</span> <span style="color: #000000;">max_delta</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">max</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_abs</span><span style="color: #0000FF;">(</span><span style="color: #7060A8;">sq_sub</span><span style="color: #0000FF;">(</span><span style="color: #000000;">counts</span><span style="color: #0000FF;">,</span><span style="color: #000000;">av</span><span style="color: #0000FF;">)))</span>
<span style="color: #008080;">return</span> <span style="color: #000000;">max_delta</span><span style="color: #0000FF;"><</span><span style="color: #000000;">delta</span><span style="color: #0000FF;">*</span><span style="color: #000000;">av</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">function</span> <span style="color: #000000;">rand7</span><span style="color: #0000FF;">()</span>
<span style="color: #008080;">return</span> <span style="color: #7060A8;">rand</span><span style="color: #0000FF;">(</span><span style="color: #000000;">7</span><span style="color: #0000FF;">)</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">function</span>
<span style="color: #008080;">constant</span> <span style="color: #000000;">flats</span> <span style="color: #0000FF;">=</span> <span style="color: #0000FF;">{</span><span style="color: #008000;">"impossible"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"not flat"</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"flat"</span><span style="color: #0000FF;">}</span>
<span style="color: #008080;">for</span> <span style="color: #000000;">p</span><span style="color: #0000FF;">=</span><span style="color: #000000;">2</span> <span style="color: #008080;">to</span> <span style="color: #000000;">7</span> <span style="color: #008080;">do</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">n</span> <span style="color: #0000FF;">=</span> <span style="color: #7060A8;">power</span><span style="color: #0000FF;">(</span><span style="color: #000000;">10</span><span style="color: #0000FF;">,</span><span style="color: #000000;">p</span><span style="color: #0000FF;">)</span>
<span style="color: #000080;font-style:italic;">-- n = n+7-remainder(n,7)</span>
<span style="color: #004080;">integer</span> <span style="color: #000000;">flat</span> <span style="color: #0000FF;">=</span> <span style="color: #000000;">check</span><span style="color: #0000FF;">(</span><span style="color: #000000;">rand7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">7</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">n</span><span style="color: #0000FF;">,</span> <span style="color: #000000;">0.005</span><span style="color: #0000FF;">)</span>
<span style="color: #7060A8;">printf</span><span style="color: #0000FF;">(</span><span style="color: #000000;">1</span><span style="color: #0000FF;">,</span><span style="color: #008000;">"%d iterations: %s\n"</span><span style="color: #0000FF;">,{</span><span style="color: #000000;">n</span><span style="color: #0000FF;">,</span><span style="color: #000000;">flats</span><span style="color: #0000FF;">[</span><span style="color: #000000;">flat</span><span style="color: #0000FF;">+</span><span style="color: #000000;">2</span><span style="color: #0000FF;">]})</span>
<span style="color: #008080;">end</span> <span style="color: #008080;">for</span>
<!--</syntaxhighlight>-->
{{out}}
<pre>
100 iterations: impossible
1000 iterations: impossible
10000 iterations: not flat
100000 iterations: not flat
1000000 iterations: flat
10000000 iterations: flat
</pre>
At the specified 0.5%, 1000000 iterations is occasionally not flat, and 10000 is sometimes flat at 3%.<br>
As shown above, it is not mathematically possible to distribute 1000 over 7 bins with <= 0.5% variance.<br>
At 100 iterations, the permitted range is ~14.21..14.36, so you could not get even one bin right.<br>
At 1000 iterations, 142 is too low (and 144 too high), they would all have to be 143, but 7*143=1001.<br>
The commented-out adjustment to n (as Raku) changes the "1000 impossible" result to "1001 not flat", <br>
except of course for the one-in-however-many-gazillion chance of getting exactly 143 of each.
 
=={{header|PicoLisp}}==
Line 1,007 ⟶ 1,541:
(one-tenth of a percent), and a 'prg' code body (i.e. an arbitrary number of
executable expressions).
<langsyntaxhighlight PicoLisplang="picolisp">(de checkDistribution (Cnt Pm . Prg)
(let Res NIL
(do Cnt (accu 'Res (run Prg 1) 1))
Line 1,015 ⟶ 1,549:
Max (*/ N (+ 1000 Pm) 1000) )
(for R Res
(prinl (cdr R) " " (if (>= Max (cdr R) Min) "Good" "Bad")) ) ) ) )</langsyntaxhighlight>
Output:
<pre>: (checkDistribution 100000 5 (rand 1 7))
Line 1,027 ⟶ 1,561:
 
=={{header|PureBasic}}==
<langsyntaxhighlight PureBasiclang="purebasic">Prototype RandNum_prt()
 
Procedure.s distcheck(*function.RandNum_prt, repetitions, delta.d)
Line 1,057 ⟶ 1,591:
EndProcedure
 
MessageRequester("Results", distcheck(@dice7(), 1000000, 0.20))</langsyntaxhighlight>
A small delta was chosen to increase the chance of a skewed result in the sample output:
<pre>Distribution check:
Line 1,070 ⟶ 1,604:
=={{header|Python}}==
{{works with|Python|3.1}}
<langsyntaxhighlight lang="python">from collections import Counter
from pprint import pprint as pp
 
Line 1,085 ⟶ 1,619:
for key, count in sorted(bin.items()) ]
)
pp(dict(bin))</langsyntaxhighlight>
Sample output:
<pre>>>> distcheck(dice5, 1000000, 1)
Line 1,096 ⟶ 1,630:
for key, count in sorted(bin.items()) ]
AssertionError: Bin distribution skewed from 200 +/- 2: [(1, 4), (2, -33), (3, 6), (4, 11), (5, 12)]</pre>
 
=={{header|Quackery}}==
 
The word <code>distribution</code> tests a specified word (Quackery function) which should return numbers in the range 1 to 7 inclusive. The word <code>dice7</code>, which satisfies this requirement, is defined at [[Seven-sided dice from five-sided dice#Quackery]].
 
<syntaxhighlight lang="quackery"> [ stack [ 0 0 0 0 0 0 0 ] ] is bins ( --> s )
 
[ 7 times
[ 0 bins take
i poke
bins put ] ] is emptybins ( --> )
 
[ bins share over peek
1+ bins take rot poke
bins put ] is bincrement ( n --> )
[ emptybins
over 7 / temp put
swap times
[ over do 1 -
bincrement ]
bins share dup echo cr
witheach
[ temp share - abs
over > if
[ say "Number of "
i^ 1+ echo
say "s is sketchy."
cr ] ]
2drop temp release ] is distribution ( x n n --> )</syntaxhighlight>
 
{{out}}
 
Testing in the Quackery shell.
 
<pre>/O> ' dice7 1000 20 distribution
...
[ 131 123 160 144 156 145 141 ]
 
Stack empty.
 
/O> ' dice7 1000 10 distribution
...
[ 137 138 130 160 143 150 142 ]
Number of 3s is sketchy.
Number of 4s is sketchy.
</pre>
 
=={{header|R}}==
<langsyntaxhighlight lang="r">distcheck <- function(fn, repetitions=1e4, delta=3)
{
if(is.character(fn))
Line 1,117 ⟶ 1,698:
data.frame(value=names(counts), counts=as.vector(counts), status=status)
}
distcheck(dice7.vec)</langsyntaxhighlight>
 
=={{header|Racket}}==
Line 1,124 ⟶ 1,705:
Returns a pair of a boolean stating uniformity and either the "uniform" distribution or a report of the first skew number found.
 
<langsyntaxhighlight lang="racket">#lang racket
(define (pretty-fraction f)
(if (integer? f) f
Line 1,160 ⟶ 1,741:
(test-uniformity/naive straight-die 1000 5)
; Test whether a biased die fails:
(test-uniformity/naive crooked-die 1000 5)</langsyntaxhighlight>
 
{{out}}
Line 1,166 ⟶ 1,747:
'(#t (1 . 169) (2 . 185) (3 . 184) (4 . 163) (5 . 144) (6 . 155))
'(#f . "test-uniformity/naive distribution of #<procedure:crooked-die> potentially skewed for 6. expected 166 2/3 got 262")</pre>
 
=={{header|Raku}}==
(formerly Perl 6)
Since the tested function is rolls of a 7 sided die, the test numbers are magnitudes of 10<sup>x</sup> bumped up to the closest multiple of 7. This reduces spurious error from there not being an integer expected value.
<syntaxhighlight lang="raku" line>my $d7 = 1..7;
sub roll7 { $d7.roll };
 
my $threshold = 3;
 
for 14, 105, 1001, 10003, 100002, 1000006 -> $n
{ dist( $n, $threshold, &roll7 ) };
 
 
sub dist ( $n is copy, $threshold, &producer ) {
my @dist;
my $expect = $n / 7;
say "Expect\t",$expect.fmt("%.3f");
loop ($_ = $n; $n; --$n) { @dist[&producer()]++; }
for @dist.kv -> $i, $v is copy {
next unless $i;
$v //= 0;
my $pct = ($v - $expect)/$expect*100;
printf "%d\t%d\t%+.2f%% %s\n", $i, $v, $pct,
($pct.abs > $threshold ?? '- skewed' !! '');
}
say '';
}</syntaxhighlight>
Sample output:
<pre>
Expect 2.000
1 2 +0.00%
2 3 +50.00% - skewed
3 2 +0.00%
4 2 +0.00%
5 3 +50.00% - skewed
6 0 -100.00% - skewed
7 2 +0.00%
 
Expect 15.000
1 15 +0.00%
2 17 +13.33% - skewed
3 13 -13.33% - skewed
4 16 +6.67% - skewed
5 14 -6.67% - skewed
6 16 +6.67% - skewed
7 14 -6.67% - skewed
 
Expect 143.000
1 134 -6.29% - skewed
2 142 -0.70%
3 141 -1.40%
4 137 -4.20% - skewed
5 142 -0.70%
6 170 +18.88% - skewed
7 135 -5.59% - skewed
 
Expect 1429.000
1 1396 -2.31%
2 1468 +2.73%
3 1405 -1.68%
4 1442 +0.91%
5 1453 +1.68%
6 1417 -0.84%
7 1422 -0.49%
 
Expect 14286.000
1 14222 -0.45%
2 14320 +0.24%
3 14326 +0.28%
4 14425 +0.97%
5 14140 -1.02%
6 14275 -0.08%
7 14294 +0.06%
 
Expect 142858.000
1 142510 -0.24%
2 142436 -0.30%
3 142438 -0.29%
4 143152 +0.21%
5 142905 +0.03%
6 143232 +0.26%
7 143333 +0.33%
</pre>
 
=={{header|REXX}}==
<langsyntaxhighlight lang="rexx">/*REXX pgmprogram simulates a #number of trials of a random digit, and show it's skew %. */
parse arg ffunc ttimes ddelta sseed . /*obtain arguments (options). from C.L. */
if f func=='' | f func=='",'" then f func= 'RANDOM' /*function funcnot ¬specified? Use default.*/
if ttimes=='' | ttimes=='",'" then ttimes= 1000000 /*times /*times" " " " */
if ddelta=='' | ddelta=='",'" then ddelta= 1/2 /*delta% " /*delta% " " " */
if s\==datatype(seed, 'W' ) then call random ,,sseed /*use some RAND seed for repeatibilityrepeatability.*/
highDig= 9 /*use this var for the highest digit. */
!.= 0 /*zeroinitialize all possible random trials*/
do j=1times for t /* [↓] perform a lotbunch of trials. */
if ffunc=='RANDOM' then ?= random(0,highDig) /*randomuse funcRANDOM function.*/
else interpret '?='f func "(0,"highDig')' /* user" specified " func.*/
!.?= !.? + 1 /*bump the invocation counter.*/
end /*jtimes*/ /* [↑] store trials ───► pigeonholes. */
/* [↓] compute the digdigit's skewness. */
g=t times / (1 + highDig) /*calculate #number of each digit throw.*/
OK?w='OK skewed' max(9, length( commas(times) ) ) /*wordsmaximum tolength showof skewed ornumber if OKof trials. */
wpad=max left(8'',length(t) 9) /*maximumthis lengthis ofused #for ofoutput trialsindentation. */
say pad=left( 'digit',9) center(" hits", w) ' skew ' "skew %" 'result' /*this is used for indentationheader. */
say sep /*display a separator line. */
say pad 'digit' center("hits",w) ' skew ' "skew%" 'result' /*hdr. */
/** [↑] show header and the separator.*/
say pad '─────' center('',w,'─') '──────' "─────" '──────' /*sep. */
do k=0 to highDig /**process [↑]each of showthe headerpossible &digits. separator.*/
do k skew=0 g - !.k to highDig /*processcalculate eachthe of theskew possible # for the digit. */
skew=g-!.k skewPC= (1 - (g - abs(skew)) / g) * 100 /* " /*calculate" the skew for the" percentage for dig.*/
skewPC= say pad center(1-(g-abs(skew))/gk, 5)*100 /* " right( commas(!.k), "w) " right(skew, 6) percentage. */,
ok= right( format(skewPC, , 3), 6) center( word('ok? skewed', 1+(skewPC>ddelta)), 6) /*it's gotta be one or the other.*/
end /*k*/
say pad center(k,5) right(!.k,w) right(skew,6) format(skewPC,,3) ok
say sep /*display a separator line. */
end /*k*/
y= 5+1+w+1+6+1+6+1+6 /*width + seps*/
say pad center(" (with " commas(times) ' trials)' , y) /*# trials. */
say pad center(" (skewed when exceeds " delta'%)' , y) /*skewed note.*/
exit 0 /*stick a fork in it, we're all done. */
/*──────────────────────────────────────────────────────────────────────────────────────*/
commas: parse arg _; do jc=length(_)-3 to 1 by -3; _=insert(',', _, jc); end; return _
sep: say pad '─────' center('', w, '─') '──────' "──────" '──────'; return</syntaxhighlight>
{{out|output|text=&nbsp; when using the default inputs:}}
<pre>
digit hits skew skew % result
───── ───────── ────── ────── ──────
0 99,739 261 0.261 ok
1 99,819 181 0.181 ok
2 100,463 -463 0.463 ok
3 99,787 213 0.213 ok
4 99,632 368 0.368 ok
5 100,787 -787 0.787 skewed
6 99,704 296 0.296 ok
7 99,605 395 0.395 ok
8 100,488 -488 0.488 ok
9 99,976 24 0.024 ok
───── ───────── ────── ───── ──────
(with 1,000,000 trials)
(skewed when exceeds 0.5%)
</pre>
 
=={{header|Ring}}==
say pad '─────' center('',w,'─') '──────' "─────" '──────' /*sep. */
<syntaxhighlight lang="ring">
y=5+1+w+1+6+1+6+1+6 /*width*/
# Project : Verify distribution uniformity/Naive
say pad center(" (with " t ' trials)',y) /*info.*/
 
say pad center(" (skewed when exceeds " d'%)',y) /*info.*/
maxrnd = 7
/*stick a fork in it, we're done.*/</lang>
for r = 2 to 5
Execution note: &nbsp; quite a few runs were needed and the skew% lowered before a skewed result was obtained.
check = distcheck(pow(10,r), 0.05)
<br><br>
see "over " + pow(10,r) + " runs dice5 " + nl
'''output''' using the default inputs:
if check
see "failed distribution check with " + check + " bin(s) out of range" + nl
else
see "passed distribution check" + nl
ok
next
func distcheck(repet, delta)
m = 1
s = 0
bins = list(maxrnd)
for i = 1 to repet
r = dice5() + 1
bins[r] = bins[r] + 1
if r>m m = r ok
next
for i = 1 to m
if bins[i]/(repet/m) > 1+delta s = s + 1 ok
if bins[i]/(repet/m) < 1-delta s = s + 1 ok
next
return s
func dice5
return random(5)
</syntaxhighlight>
Output:
<pre>
Over 100 runs dice5 failed distribution check with 3 bin(s) out of range
Over 1000 runs dice5 failed distribution check with 1 bin(s) out of range
Over 10000 runs dice5 passed distribution check
Over 100000 runs dice5 passed distribution check
</pre>
 
=={{header|RPL}}==
Calculated frequencies are negative when below/above the tolerance given by <code>delta</code>.
 
<code>DICE7</code> is defined at [[Seven-sided dice from five-sided dice#RPL|Seven-sided dice from five-sided dice]]
≪ 1 → func n delta bins
≪ { 1 } 0 CON
1 n '''FOR''' j
func EVAL
'''IF''' bins OVER < '''THEN'''
DUP 'bins' STO
1 →LIST RDM bins
'''END'''
DUP2 GET 1 + PUT
'''NEXT'''
1 bins '''FOR''' j
DUP j GET
'''IF'''
DUP n bins / %CH 100 / ABS
delta >
'''THEN''' NEG j SWAP PUT '''ELSE''' DROP '''END'''
'''NEXT'''
≫ ≫ '<span style="color:blue">UNIF?</span>' STO
 
≪ <span style="color:blue">DICE7</span> ≫ 10000 .05 <span style="color:blue">UNIF?</span>
≪ 6 RAND * CEIL ≫ 1000 .05 <span style="color:blue">UNIF?</span>
{{out}}
<pre>
2: [ 1439 1404 1413 1410 1424 1486 1424 ]
digit hits skew skew% result
1: [ 169 172 -158 163 171 167 ]
───── ──────── ────── ───── ──────
0 99790 210 0.210 OK
1 99564 436 0.436 OK
2 100061 -61 0.061 OK
3 99797 203 0.203 OK
4 99877 123 0.123 OK
5 99578 422 0.422 OK
6 99889 111 0.111 OK
7 100619 -619 0.619 skewed
8 100414 -414 0.414 OK
9 100411 -411 0.411 OK
───── ──────── ────── ───── ──────
(with 1000000 trials)
(skewed when exceeds 0.5%)
</pre>
 
=={{header|Ruby}}==
{{trans|Tcl}}
<langsyntaxhighlight lang="ruby">def distcheck(n, delta=1)
unless block_given?
raise ArgumentError, "pass a block to this method"
Line 1,250 ⟶ 1,987:
p e
end
end</langsyntaxhighlight>
 
{{out}}
Line 1,267 ⟶ 2,004:
 
=={{header|Run BASIC}}==
<langsyntaxhighlight lang="runbasic">s$ = "#########################"
dim num(100)
for i = 1 to 1000
Line 1,276 ⟶ 2,013:
for i = 1 to 10
print using("###",i);" "; using("#####",num(i));" ";left$(s$,num(i) / 5)
next i</langsyntaxhighlight><pre>
1 90 ##################
2 110 ######################
Line 1,287 ⟶ 2,024:
9 82 ################
10 92 ##################*</pre>
 
=={{header|Scala}}==
===Imperative, ugly, mutable data===
<syntaxhighlight lang="scala">object DistrubCheck1 extends App {
 
private def distCheck(f: () => Int, nRepeats: Int, delta: Double): Unit = {
val counts = scala.collection.mutable.Map[Int, Int]()
 
for (_ <- 0 until nRepeats)
counts.updateWith(f()) {
case Some(count) => Some(count + 1)
case None => Some(1)
}
 
val target: Double = nRepeats.toDouble / counts.size
val deltaCount: Int = (delta / 100.0 * target).toInt
counts.foreach {
case (k, v) =>
if (math.abs(target - v) >= deltaCount)
println(f"distribution potentially skewed for $k%s: $v%d")
}
counts.toIndexedSeq.foreach(entry => println(f"${entry._1}%d ${entry._2}%d"))
}
 
distCheck(() => 1 + util.Random.nextInt(5), 1_000_000, 1)
 
}</syntaxhighlight>
 
===Functional Style===
{{Out}}Best seen running in your browser either by [https://scalafiddle.io/sf/oYJWUvX/0 ScalaFiddle (ES aka JavaScript, non JVM)] or [https://scastie.scala-lang.org/O513W3VoQ7ulspUMnGvTiQ Scastie (remote JVM)].
<syntaxhighlight lang="scala">object DistrubCheck2 extends App {
private def distCheck(f: () => Int, nRepeats: Int, delta: Double): Unit = {
val counts: Map[Int, Int] =
(0 until nRepeats).map(_ => f()).groupBy(identity).map { case (k, v) => (k, v.size) }
val target = nRepeats / counts.size.toDouble
 
counts.withFilter { case (_, v) => math.abs(target - v) >= (delta / 100.0 * target) }
.foreach { case (k, v) => println(f"distribution potentially skewed for $k%s: $v%d") }
 
counts.toIndexedSeq.foreach(entry => println(f"${entry._1}%d ${entry._2}%d"))
}
 
distCheck(() => 1 + util.Random.nextInt(5), 1_000_000, 1)
 
}</syntaxhighlight>
 
=={{header|Tcl}}==
<langsyntaxhighlight lang="tcl">proc distcheck {random times {delta 1}} {
for {set i 0} {$i<$times} {incr i} {incr vals([uplevel 1 $random])}
set target [expr {$times / [array size vals]}]
Line 1,299 ⟶ 2,081:
foreach k [lsort -integer [array names vals]] {lappend result $k $vals($k)}
return $result
}</langsyntaxhighlight>
Demonstration:
<langsyntaxhighlight lang="tcl"># First, a uniformly distributed random variable
puts [distcheck {expr {int(10*rand())}} 100000]
 
# Now, one that definitely isn't!
puts [distcheck {expr {rand()>0.95}} 100000]</langsyntaxhighlight>
Which produces this output (error in red):
0 10003 1 9851 2 10058 3 10193 4 10126 5 10002 6 9852 7 9964 8 9957 9 9994
Line 1,311 ⟶ 2,093:
 
=={{header|VBScript}}==
<langsyntaxhighlight lang="vb">Option Explicit
 
sub verifydistribution(calledfunction, samples, delta)
Line 1,334 ⟶ 2,116:
& ", desired limit is " & FormatPercent(delta, 2) & "."
if maxdiff > delta then wscript.echo "Skewed!" else wscript.echo "Smooth!"
end sub</langsyntaxhighlight>
Demonstration with included [[Seven-sided dice from five-sided dice#VBScript]] code:
<langsyntaxhighlight lang="vb">verifydistribution "dice7", 1000, 0.03
verifydistribution "dice7", 100000, 0.03</langsyntaxhighlight>
Which produces this output:
Running "dice7" 1000 times...
Line 1,361 ⟶ 2,143:
Maximum found variation is 0.94%, desired limit is 3.00%.
Smooth!
 
=={{header|V (Vlang)}}==
{{trans|go}}
<syntaxhighlight lang="v (vlang)">import rand
import rand.seed
import math
// "given"
fn dice5() int {
return rand.intn(5) or {0} + 1
}
// fntion specified by task "Seven-sided dice from five-sided dice"
fn dice7() int {
mut i := 0
for {
i = 5*dice5() + dice5()
if i < 27 {
break
}
}
return (i / 3) - 1
}
// fntion specified by task "Verify distribution uniformity/Naive"
//
// Parameter "f" is expected to return a random integer in the range 1..n.
// (Values out of range will cause an unceremonious crash.)
// "Max" is returned as an "indication of distribution achieved."
// It is the maximum delta observed from the count representing a perfectly
// uniform distribution.
// Also returned is a boolean, true if "max" is less than threshold
// parameter "delta."
fn dist_check(f fn() int, n int,
repeats int, delta f64) (f64, bool) {
mut max := 0.0
mut count := []int{len: n}
for _ in 0..repeats {
count[f()-1]++
}
expected := f64(repeats) / f64(n)
for c in count {
max = math.max(max, math.abs(f64(c)-expected))
}
return max, max < delta
}
// Driver, produces output satisfying both tasks.
fn main() {
rand.seed(seed.time_seed_array(2))
calls := 1000000
mut max, mut flat_enough := dist_check(dice7, 7, calls, 500)
println("Max delta: $max Flat enough: $flat_enough")
max, flat_enough = dist_check(dice7, 7, calls, 500)
println("Max delta: $max Flat enough: $flat_enough")
}</syntaxhighlight>
{{out}}
<pre>
Max delta: 723.8571428571304 Flat enough: false
Max delta: 435.1428571428696 Flat enough: true
</pre>
 
=={{header|Wren}}==
{{trans|Kotlin}}
{{libheader|Wren-fmt}}
{{libheader|Wren-sort}}
<syntaxhighlight lang="wren">import "random" for Random
import "./fmt" for Fmt
import "./sort" for Sort
 
var r = Random.new()
 
var dice5 = Fn.new { 1 + r.int(5) }
 
var checkDist = Fn.new { |gen, nRepeats, tolerance|
var occurs = {}
for (i in 1..nRepeats) {
var d = gen.call()
occurs[d] = occurs.containsKey(d) ? occurs[d] + 1 : 1
}
var expected = (nRepeats/occurs.count).floor
var maxError = (expected*tolerance/100).floor
System.print("Repetitions = %(nRepeats), Expected = %(expected)")
System.print("Tolerance = %(tolerance)\%, Max Error = %(maxError)\n")
System.print("Integer Occurrences Error Acceptable")
var f = " $d $5d $5d $s"
var allAcceptable = true
occurs = occurs.toList
Sort.quick(occurs)
for (me in occurs) {
var error = (me.value - expected).abs
var acceptable = (error <= maxError) ? "Yes" : "No"
if (acceptable == "No") allAcceptable = false
Fmt.print(f, me.key, me.value, error, acceptable)
}
System.print("\nAcceptable overall: %(allAcceptable ? "Yes" : "No")")
}
 
checkDist.call(dice5, 1e6, 0.5)
System.print()
checkDist.call(dice5, 1e5, 0.5)</syntaxhighlight>
 
{{out}}
Sample run:
<pre>
Repetitions = 1000000, Expected = 200000
Tolerance = 0.5%, Max Error = 1000
 
Integer Occurrences Error Acceptable
1 199599 401 Yes
2 199676 324 Yes
3 200561 561 Yes
4 200647 647 Yes
5 199517 483 Yes
 
Acceptable overall: Yes
 
Repetitions = 100000, Expected = 20000
Tolerance = 0.5%, Max Error = 100
 
Integer Occurrences Error Acceptable
1 19780 220 No
2 20005 5 Yes
3 20206 206 No
4 19920 80 Yes
5 20089 89 Yes
 
Acceptable overall: No
</pre>
 
=={{header|zkl}}==
This tests the random spread over 0..9. It starts at 10 samples and doubles the sample size until the spread is within 0.1% of 10% for each bucket.
<langsyntaxhighlight lang="zkl">fcn rtest(N){
dist:=L(0,0,0,0,0,0,0,0,0,0);
do(N){n:=(0).random(10); dist[n]=dist[n]+1}
Line 1,375 ⟶ 2,285:
 
n:=10;
while(not rtest(n)) {n*=2}</langsyntaxhighlight>
{{out}}
Reported numbers is the percent that bucket has of all samples.
9,476

edits