' Random distributions: uniform, normal, exponential, Bernoulli, Poisson
#COMPILE EXE
#DIM ALL

FUNCTION UniformRand(BYVAL min AS DOUBLE, BYVAL max AS DOUBLE) AS DOUBLE
    FUNCTION = min + (max - min) * RND
END FUNCTION

FUNCTION NormalRand(BYVAL mean AS DOUBLE, BYVAL stddev AS DOUBLE) AS DOUBLE
    LOCAL u1  AS DOUBLE
    LOCAL u2  AS DOUBLE
    LOCAL r  AS DOUBLE
    LOCAL theta  AS DOUBLE
    u1 = RND
    IF u1 < 0.000000000000001 THEN u1 = 0.000000000000001
    u2 = RND
    r = SQR(0.0 - 2.0 * LOG(u1))
    theta = 6.283185307179586 * u2
    FUNCTION = mean + stddev * r * COS(theta)
END FUNCTION

FUNCTION ExponentialRand(BYVAL lambda AS DOUBLE) AS DOUBLE
    LOCAL u AS DOUBLE
    u = RND
    IF u < 0.000000000000001 THEN u = 0.000000000000001
    FUNCTION = (0.0 - LOG(u)) / lambda
END FUNCTION

FUNCTION BernoulliRand(BYVAL p AS DOUBLE) AS LONG
    IF RND < p THEN FUNCTION = 1 ELSE FUNCTION = 0
END FUNCTION

FUNCTION PoissonRand(BYVAL lambda AS DOUBLE) AS LONG
    LOCAL L  AS DOUBLE
    LOCAL p  AS DOUBLE
    LOCAL u  AS DOUBLE
    LOCAL k AS LONG
    L = EXP(-lambda)
    k = 0
    p = 1.0
    DO
        k = k + 1
        u = RND
        IF u < 0.000000000000001 THEN u = 0.000000000000001
        p = p * u
        IF p < L THEN EXIT LOOP
    LOOP
    FUNCTION = k - 1
END FUNCTION

FUNCTION SampleMean(BYVAL n AS LONG) AS DOUBLE
    LOCAL i AS LONG
    LOCAL sum AS DOUBLE
    sum = 0.0
    FOR i = 1 TO n
        sum = sum + UniformRand(0.0, 1.0)
    NEXT i
    FUNCTION = sum / n
END FUNCTION

FUNCTION PBMAIN() AS LONG
    LOCAL i  AS LONG
    LOCAL n  AS LONG
    LOCAL ones  AS LONG
    PRINT "=== Random Distributions ==="
    PRINT
    RANDOMIZE TIMER
    n = 10
    PRINT "Uniform[0,1]:"
    FOR i = 1 TO 5
        PRINT "  " + FORMAT$(UniformRand(0.0, 1.0), "#0.000")
    NEXT i
    PRINT
    PRINT "Normal(0,1):"
    FOR i = 1 TO 5
        PRINT "  " + FORMAT$(NormalRand(0.0, 1.0), "#0.000")
    NEXT i
    PRINT
    PRINT "Exponential(1):"
    FOR i = 1 TO 5
        PRINT "  " + FORMAT$(ExponentialRand(1.0), "#0.000")
    NEXT i
    PRINT
    ones = 0
    FOR i = 1 TO n
        IF BernoulliRand(0.5) THEN ones = ones + 1
    NEXT i
    PRINT "Bernoulli(0.5): " + FORMAT$(ones) + " ones / " + FORMAT$(n)
    PRINT
    PRINT "Poisson(3):"
    FOR i = 1 TO 5
        PRINT "  " + FORMAT$(PoissonRand(3.0))
    NEXT i
    PRINT
    PRINT "Uniform(10,20): " + FORMAT$(UniformRand(10.0, 20.0), "#0.00")
    PRINT "Normal(100,15): " + FORMAT$(NormalRand(100.0, 15.0), "#0.0")
    PRINT "Sample mean(100): " + FORMAT$(SampleMean(100), "#0.000")
    PRINT
    PRINT "Distribution tests complete."
    FUNCTION = 0
END FUNCTION
