Modified random distribution: Difference between revisions
(Added Wren) |
(Added Go) |
||
Line 23: | Line 23: | ||
Show your output here, on this page. |
Show your output here, on this page. |
||
=={{header|Go}}== |
|||
{{trans|Wren}} |
|||
<lang go>package main |
|||
import ( |
|||
"fmt" |
|||
"math" |
|||
"math/rand" |
|||
"strings" |
|||
"time" |
|||
) |
|||
func rng(modifier func(x float64) float64) float64 { |
|||
for { |
|||
r1 := rand.Float64() |
|||
r2 := rand.Float64() |
|||
if r2 < modifier(r1) { |
|||
return r1 |
|||
} |
|||
} |
|||
} |
|||
func commatize(n int) string { |
|||
s := fmt.Sprintf("%d", n) |
|||
if n < 0 { |
|||
s = s[1:] |
|||
} |
|||
le := len(s) |
|||
for i := le - 3; i >= 1; i -= 3 { |
|||
s = s[0:i] + "," + s[i:] |
|||
} |
|||
if n >= 0 { |
|||
return s |
|||
} |
|||
return "-" + s |
|||
} |
|||
func main() { |
|||
rand.Seed(time.Now().UnixNano()) |
|||
modifier := func(x float64) float64 { |
|||
if x < 0.5 { |
|||
return 2 * (0.5 - x) |
|||
} |
|||
return 2 * (x - 0.5) |
|||
} |
|||
const ( |
|||
N = 100000 |
|||
NUM_BINS = 20 |
|||
HIST_CHAR = "■" |
|||
HIST_CHAR_SIZE = 125 |
|||
) |
|||
bins := make([]int, NUM_BINS) // all zero by default |
|||
binSize := 1.0 / NUM_BINS |
|||
for i := 0; i < N; i++ { |
|||
rn := rng(modifier) |
|||
bn := int(math.Floor(rn / binSize)) |
|||
bins[bn]++ |
|||
} |
|||
fmt.Println("Modified random distribution with", commatize(N), "samples in range [0, 1):\n") |
|||
fmt.Println(" Range Number of samples within that range") |
|||
for i := 0; i < NUM_BINS; i++ { |
|||
hist := strings.Repeat(HIST_CHAR, int(math.Round(float64(bins[i])/HIST_CHAR_SIZE))) |
|||
fi := float64(i) |
|||
fmt.Printf("%4.2f ..< %4.2f %s %s\n", binSize*fi, binSize*(fi+1), hist, commatize(bins[i])) |
|||
} |
|||
}</lang> |
|||
{{out}} |
|||
Specimen run: |
|||
<pre> |
|||
Modified random distribution with 100,000 samples in range [0, 1): |
|||
Range Number of samples within that range |
|||
0.00 ..< 0.05 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,396 |
|||
0.05 ..< 0.10 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,434 |
|||
0.10 ..< 0.15 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,484 |
|||
0.15 ..< 0.20 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,576 |
|||
0.20 ..< 0.25 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,516 |
|||
0.25 ..< 0.30 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,625 |
|||
0.30 ..< 0.35 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,478 |
|||
0.35 ..< 0.40 ■■■■■■■■■■■■■■■■■■■■ 2,506 |
|||
0.40 ..< 0.45 ■■■■■■■■■■■■ 1,504 |
|||
0.45 ..< 0.50 ■■■■ 505 |
|||
0.50 ..< 0.55 ■■■■ 511 |
|||
0.55 ..< 0.60 ■■■■■■■■■■■■■ 1,563 |
|||
0.60 ..< 0.65 ■■■■■■■■■■■■■■■■■■■■■ 2,582 |
|||
0.65 ..< 0.70 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,520 |
|||
0.70 ..< 0.75 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,326 |
|||
0.75 ..< 0.80 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,489 |
|||
0.80 ..< 0.85 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,589 |
|||
0.85 ..< 0.90 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,472 |
|||
0.90 ..< 0.95 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,592 |
|||
0.95 ..< 1.00 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,332 |
|||
</pre> |
|||
=={{header|Julia}}== |
=={{header|Julia}}== |
Revision as of 12:14, 26 February 2021
Given a random number generator, (rng), generating numbers in the range 0.0 .. 1.0 called rgen, for example; and a function modifier(x) taking an number in the same range and generating the probability that the input should be generated, in the same range 0..1; then implement the following algorithm for generating random numbers to the probability given by function modifier:
while True: random1 = rgen() random2 = rgen() if random2 < modifier(random1): answer = random1 break endif endwhile
- Task
- Create a modifier function that generates a 'V' shaped probability of number generation using something like, for example:
modifier(x) = 2*(0.5 - x) if x < 0.5 else 2*(x - 0.5)
- Create a generator of random numbers with probabilities modified by the above function.
- Generate >= 10,000 random numbers subject to the probability modification.
- Output a textual histogram with from 11 to 21 bins showing the distribution of the random numbers generated.
Show your output here, on this page.
Go
<lang go>package main
import (
"fmt" "math" "math/rand" "strings" "time"
)
func rng(modifier func(x float64) float64) float64 {
for { r1 := rand.Float64() r2 := rand.Float64() if r2 < modifier(r1) { return r1 } }
}
func commatize(n int) string {
s := fmt.Sprintf("%d", n) if n < 0 { s = s[1:] } le := len(s) for i := le - 3; i >= 1; i -= 3 { s = s[0:i] + "," + s[i:] } if n >= 0 { return s } return "-" + s
}
func main() {
rand.Seed(time.Now().UnixNano()) modifier := func(x float64) float64 { if x < 0.5 { return 2 * (0.5 - x) } return 2 * (x - 0.5) } const ( N = 100000 NUM_BINS = 20 HIST_CHAR = "■" HIST_CHAR_SIZE = 125 ) bins := make([]int, NUM_BINS) // all zero by default binSize := 1.0 / NUM_BINS for i := 0; i < N; i++ { rn := rng(modifier) bn := int(math.Floor(rn / binSize)) bins[bn]++ }
fmt.Println("Modified random distribution with", commatize(N), "samples in range [0, 1):\n") fmt.Println(" Range Number of samples within that range") for i := 0; i < NUM_BINS; i++ { hist := strings.Repeat(HIST_CHAR, int(math.Round(float64(bins[i])/HIST_CHAR_SIZE))) fi := float64(i) fmt.Printf("%4.2f ..< %4.2f %s %s\n", binSize*fi, binSize*(fi+1), hist, commatize(bins[i])) }
}</lang>
- Output:
Specimen run:
Modified random distribution with 100,000 samples in range [0, 1): Range Number of samples within that range 0.00 ..< 0.05 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,396 0.05 ..< 0.10 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,434 0.10 ..< 0.15 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,484 0.15 ..< 0.20 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,576 0.20 ..< 0.25 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,516 0.25 ..< 0.30 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,625 0.30 ..< 0.35 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,478 0.35 ..< 0.40 ■■■■■■■■■■■■■■■■■■■■ 2,506 0.40 ..< 0.45 ■■■■■■■■■■■■ 1,504 0.45 ..< 0.50 ■■■■ 505 0.50 ..< 0.55 ■■■■ 511 0.55 ..< 0.60 ■■■■■■■■■■■■■ 1,563 0.60 ..< 0.65 ■■■■■■■■■■■■■■■■■■■■■ 2,582 0.65 ..< 0.70 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,520 0.70 ..< 0.75 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,326 0.75 ..< 0.80 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,489 0.80 ..< 0.85 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,589 0.85 ..< 0.90 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,472 0.90 ..< 0.95 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,592 0.95 ..< 1.00 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,332
Julia
<lang>using UnicodePlots
modifier(x) = (y = 2x - 1; y < 0 ? -y : y) modrands(rands1, rands2) = [x for (i, x) in enumerate(rands1) if rands2[i] < modifier(x)] histogram(modrands(rand(50000), rand(50000)), nbins = 20)
</lang>
- Output:
┌ ┐ [0.0 , 0.05) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2412 [0.05, 0.1 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2164 [0.1 , 0.15) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1850 [0.15, 0.2 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1652 [0.2 , 0.25) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1379 [0.25, 0.3 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1121 [0.3 , 0.35) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇ 903 [0.35, 0.4 ) ┤▇▇▇▇▇▇▇▇▇▇ 695 [0.4 , 0.45) ┤▇▇▇▇▇▇ 407 [0.45, 0.5 ) ┤▇▇ 118 [0.5 , 0.55) ┤▇▇ 126 [0.55, 0.6 ) ┤▇▇▇▇▇ 358 [0.6 , 0.65) ┤▇▇▇▇▇▇▇▇▇ 639 [0.65, 0.7 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇ 837 [0.7 , 0.75) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1121 [0.75, 0.8 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1332 [0.8 , 0.85) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1608 [0.85, 0.9 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 1920 [0.9 , 0.95) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2204 [0.95, 1.0 ) ┤▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 2348 └ ┘ Frequency
Python
<lang python>import random from typing import List, Callable, Optional
def modifier(x: float) -> float:
""" V-shaped, modifier(x) goes from 1 at 0 to 0 at 0.5 then back to 1 at 1.0 .
Parameters ---------- x : float Number, 0.0 .. 1.0 .
Returns ------- float Target probability for generating x; between 0 and 1.
""" return 2*(.5 - x) if x < 0.5 else 2*(x - .5)
def modified_random_distribution(modifier: Callable[[float], float],
n: int) -> List[float]: """ Generate n random numbers between 0 and 1 subject to modifier.
Parameters ---------- modifier : Callable[[float], float] Target random number gen. 0 <= modifier(x) < 1.0 for 0 <= x < 1.0 . n : int number of random numbers generated.
Returns ------- List[float] n random numbers generated with given probability.
""" d: List[float] = [] while len(d) < n: r1 = prob = random.random() if random.random() < modifier(prob): d.append(r1) return d
if __name__ == '__main__':
from collections import Counter
data = modified_random_distribution(modifier, 50_000) bins = 15 counts = Counter(d // (1 / bins) for d in data) # mx = max(counts.values()) print(" BIN, COUNTS, DELTA: HISTOGRAM\n") last: Optional[float] = None for b, count in sorted(counts.items()): delta = 'N/A' if last is None else str(count - last) print(f" {b / bins:5.2f}, {count:4}, {delta:>4}: " f"{'#' * int(40 * count / mx)}") last = count</lang>
- Output:
BIN, COUNTS, DELTA: HISTOGRAM 0.00, 6326, N/A: ######################################## 0.07, 5327, -999: ################################# 0.13, 4487, -840: ############################ 0.20, 3495, -992: ###################### 0.27, 2601, -894: ################ 0.33, 1744, -857: ########### 0.40, 914, -830: ##### 0.47, 225, -689: # 0.53, 899, 674: ##### 0.60, 1783, 884: ########### 0.67, 2623, 840: ################ 0.73, 3566, 943: ###################### 0.80, 4383, 817: ########################### 0.87, 5422, 1039: ################################## 0.93, 6205, 783: #######################################
REXX
<lang rexx>/*REXX program generates a "V" shaped probability of number generation using a modifier.*/ parse arg randn bins seed . /*obtain optional argument from the CL.*/ if randN== | randN=="," then randN= 100000 /*Not specified? Then use the default.*/ if bins== | bins=="," then bins= 20 /* " " " " " " */ if datatype(seed, 'W') then call random ,,seed /* " " " " " " */ call MRD !.= 0
do j=1 for randN; bin= @.j*bins%1 !.bin= !.bin + 1 /*bump the applicable bin counter. */ end /*j*/
mx= 0
do k=1 for randN; mx= max(mx, !.k) /*find the maximum, used for histograph*/ end /*k*/
say ' bin' say '────── ' center('(with ' commas(randN) " samples", 80 - 10)
do b=0 for bins; say format(b/bins,2,2) copies('■', 70*!.b%mx)" " commas(!.b) end /*b*/
exit 0 /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: arg ?; do jc=length(?)-3 to 1 by -3; ?=insert(',', ?, jc); end; return ? rand: return random(0, 100000) / 100000 /*──────────────────────────────────────────────────────────────────────────────────────*/ modifier: parse arg y; if y<.5 then return 2 * (.5 - y)
else return 2 * ( y - .5)
/*──────────────────────────────────────────────────────────────────────────────────────*/ MRD: #=0; @.= /*MRD: Modified Random distribution. */
do until #==randN; r= rand() /*generate a random number; assign bkup*/ if rand()>=modifier(r) then iterate /*Doesn't meet requirement? Then skip.*/ #= # + 1; @.#= r /*bump counter; assign the MRD to array*/ end /*until*/ return</lang>
- output when using the default inputs:
bin ────── (with 100,000 samples 0.00 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,476 0.05 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,471 0.10 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,528 0.15 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,403 0.20 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,593 0.25 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,541 0.30 ■■■■■■■■■■■■■■■■■■■■■■■■ 3,424 0.35 ■■■■■■■■■■■■■■■■■■ 2,514 0.40 ■■■■■■■■■■■ 1,508 0.45 ■■■ 463 0.50 ■■■ 493 0.55 ■■■■■■■■■■ 1,501 0.60 ■■■■■■■■■■■■■■■■■■ 2,508 0.65 ■■■■■■■■■■■■■■■■■■■■■■■■ 3,416 0.70 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,574 0.75 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,556 0.80 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,506 0.85 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,551 0.90 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,383 0.95 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,590
Wren
<lang ecmascript>import "random" for Random import "/fmt" for Fmt
var rgen = Random.new()
var rng = Fn.new { |modifier|
while (true) { var r1 = rgen.float() var r2 = rgen.float() if (r2 < modifier.call(r1)) { return r1 } }
}
var modifier = Fn.new { |x| (x < 0.5) ? 2 * (0.5 - x) : 2 * (x - 0.5) }
var N = 100000 var NUM_BINS = 20 var HIST_CHAR = "■" var HIST_CHAR_SIZE = 125 var bins = List.filled(NUM_BINS, 0) var binSize = 1 / NUM_BINS for (i in 0...N) {
var rn = rng.call(modifier) var bn = (rn / binSize).floor bins[bn] = bins[bn] + 1
}
Fmt.print("Modified random distribution with $,d samples in range [0, 1):\n", N) System.print(" Range Number of samples within that range") for (i in 0...NUM_BINS) {
var hist = HIST_CHAR * (bins[i] / HIST_CHAR_SIZE).round Fmt.print("$4.2f ..< $4.2f $s $,d", binSize * i, binSize * (i + 1), hist, bins[i])
}</lang>
- Output:
Specimen run:
Modified random distribution with 100,000 samples in range [0, 1): Range Number of samples within that range 0.00 ..< 0.05 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,605 0.05 ..< 0.10 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,573 0.10 ..< 0.15 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,440 0.15 ..< 0.20 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,582 0.20 ..< 0.25 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,482 0.25 ..< 0.30 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,472 0.30 ..< 0.35 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,478 0.35 ..< 0.40 ■■■■■■■■■■■■■■■■■■■■ 2,497 0.40 ..< 0.45 ■■■■■■■■■■■■ 1,519 0.45 ..< 0.50 ■■■■ 489 0.50 ..< 0.55 ■■■■ 485 0.55 ..< 0.60 ■■■■■■■■■■■■ 1,453 0.60 ..< 0.65 ■■■■■■■■■■■■■■■■■■■■ 2,477 0.65 ..< 0.70 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 3,492 0.70 ..< 0.75 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 4,453 0.75 ..< 0.80 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 5,535 0.80 ..< 0.85 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 6,480 0.85 ..< 0.90 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 7,573 0.90 ..< 0.95 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 8,372 0.95 ..< 1.00 ■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■ 9,543