RANDOM

Copyright(c) 2016 Stefano Balietti MIT Licensed

Generates pseudo-random numbers

(function(JSUS) {

    "use strict";

    function RANDOM() {}

RANDOM.random

Generates a pseudo-random floating point number between [a,b), a inclusive and b exclusive.

Params
a number The lower limit
b number The upper limit
Returns
number A random floating point number in [a,b)
    RANDOM.random = function(a, b) {
        var c;
        a = ('undefined' === typeof a) ? 0 : a;
        b = ('undefined' === typeof b) ? 0 : b;
        if (a === b) return a;

        if (b < a) {
            c = a;
            a = b;
            b = c;
        }
        return (Math.random() * (b - a)) + a;
    };

RANDOM.randomInt

Generates a pseudo-random integer between (a,b] a exclusive, b inclusive

Params
a number The lower limit
b number The upper limit
Returns
number A random integer in (a,b]
See
RANDOM.random
    RANDOM.randomInt = function(a, b) {
        if (a === b) return a;
        return Math.floor(RANDOM.random(a, b) + 1);
    };

RANDOM.sample

Generates a randomly shuffled sequence of numbers in (a,b)

Both a and b are inclued in the interval.

Params
a number The lower limit
b number The upper limit
Returns
array The randomly shuffled sequence.
See
RANDOM.seq
    RANDOM.sample = function(a, b) {
        var out;
        out = JSUS.seq(a,b);
        if (!out) return false;
        return JSUS.shuffle(out);
    };

RANDOM.getNormalGenerator

Returns a new generator of normally distributed pseudo random numbers

The generator is independent from RANDOM.nextNormal

Returns
function An independent generator
See
RANDOM.nextNormal
    RANDOM.getNormalGenerator = function() {

        return (function() {

            var oldMu, oldSigma;
            var x2, multiplier, genReady;

            return function normal(mu, sigma) {

                var x1, u1, u2, v1, v2, s;

                if ('number' !== typeof mu) {
                    throw new TypeError('nextNormal: mu must be number.');
                }
                if ('number' !== typeof sigma) {
                    throw new TypeError('nextNormal: sigma must be number.');
                }

                if (mu !== oldMu || sigma !== oldSigma) {
                    genReady = false;
                    oldMu = mu;
                    oldSigma = sigma;
                }

                if (genReady) {
                    genReady = false;
                    return (sigma * x2) + mu;
                }

                u1 = Math.random();
                u2 = Math.random();

Normalize between -1 and +1.

                v1 = (2 * u1) - 1;
                v2 = (2 * u2) - 1;

                s = (v1 * v1) + (v2 * v2);

Condition is true on average 1.27 times, with variance equal to 0.587.

                if (s >= 1) {
                    return normal(mu, sigma);
                }

                multiplier = Math.sqrt(-2 * Math.log(s) / s);

                x1 = v1 * multiplier;
                x2 = v2 * multiplier;

                genReady = true;

                return (sigma * x1) + mu;

            };
        })();
    };

RANDOM.nextNormal

Generates random numbers with Normal Gaussian distribution.

User must specify the expected mean, and standard deviation a input parameters.

Implements the Polar Method by Knuth, "The Art Of Computer Programming", p. 117.

Params
mu number The mean of the distribution param {number} sigma The standard deviation of the distribution
Returns
number A random number following a Normal Gaussian distribution
See
RANDOM.getNormalGenerator
    RANDOM.nextNormal = RANDOM.getNormalGenerator();

RANDOM.nextLogNormal

Generates random numbers with LogNormal distribution.

User must specify the expected mean, and standard deviation of the underlying gaussian distribution as input parameters.

Params
mu number The mean of the gaussian distribution
sigma number The standard deviation of the gaussian distribution
Returns
number A random number following a LogNormal distribution
See
RANDOM.nextNormal
    RANDOM.nextLogNormal = function(mu, sigma) {
        if ('number' !== typeof mu) {
            throw new TypeError('nextLogNormal: mu must be number.');
        }
        if ('number' !== typeof sigma) {
            throw new TypeError('nextLogNormal: sigma must be number.');
        }
        return Math.exp(RANDOM.nextNormal(mu, sigma));
    };

RANDOM.nextExponential

Generates random numbers with Exponential distribution.

User must specify the lambda the rate parameter of the distribution. The expected mean of the distribution is equal to Math.pow(lamba, -1).

Params
lambda number The rate parameter
Returns
number A random number following an Exponential distribution
    RANDOM.nextExponential = function(lambda) {
        if ('number' !== typeof lambda) {
            throw new TypeError('nextExponential: lambda must be number.');
        }
        if (lambda <= 0) {
            throw new TypeError('nextExponential: ' +
                                'lambda must be greater than 0.');
        }
        return - Math.log(1 - Math.random()) / lambda;
    };

RANDOM.nextBinomial

Generates random numbers following the Binomial distribution.

User must specify the probability of success and the number of trials.

Params
p number The probability of success
trials number The number of trials
Returns
number The sum of successes in n trials
    RANDOM.nextBinomial = function(p, trials) {
        var counter, sum;

        if ('number' !== typeof p) {
            throw new TypeError('nextBinomial: p must be number.');
        }
        if ('number' !== typeof trials) {
            throw new TypeError('nextBinomial: trials must be number.');
        }
        if (p < 0 || p > 1) {
            throw new TypeError('nextBinomial: p must between 0 and 1.');
        }
        if (trials < 1) {
            throw new TypeError('nextBinomial: trials must be greater than 0.');
        }

        counter = 0;
        sum = 0;

        while(counter < trials){
            if (Math.random() < p) {
                sum += 1;
            }
            counter++;
        }

        return sum;
    };

RANDOM.nextGamma

Generates random numbers following the Gamma distribution.

This function is experimental and untested. No documentation.

    RANDOM.nextGamma = function(alpha, k) {
        var intK, kDiv, alphaDiv;
        var u1, u2, u3;
        var x, i, tmp;

        if ('number' !== typeof alpha) {
            throw new TypeError('nextGamma: alpha must be number.');
        }
        if ('number' !== typeof k) {
            throw new TypeError('nextGamma: k must be number.');
        }
        if (alpha < 1) {
            throw new TypeError('nextGamma: alpha must be greater than 1.');
        }
        if (k < 1) {
            throw new TypeError('nextGamma: k must be greater than 1.');
        }

        u1 = Math.random();
        u2 = Math.random();
        u3 = Math.random();

        intK = Math.floor(k) + 3;
        kDiv = 1 / k;

        alphaDiv = 1 / alpha;

        x = 0;
        for (i = 3 ; ++i < intK ; ) {
            x += Math.log(Math.random());
        }

        x *= - alphaDiv;

        tmp = Math.log(u3) *
            (Math.pow(u1, kDiv) /
             ((Math.pow(u1, kDiv) + Math.pow(u2, 1 / (1 - k)))));

        tmp *=  - alphaDiv;

        return x + tmp;
    };

RANDOM.randomString

Creates a parametric random string

Params
len number The length of string (must be > 0). Default, 6.
chars string A code specifying which sets of characters to use. Available symbols (default 'a'): - 'a': lower case letters - 'A': upper case letters - '1': digits - '!': all remaining symbols (excluding spaces) - '_': spaces (it can be followed by an integer > 0 controlling the frequency of spaces, default = 1)
useChars boolean If TRUE, the characters of the chars parameter are used as they are instead of interpreted as special symbols. Default FALSE.
Returns
string result The random string Kudos to: http://stackoverflow.com/questions/10726909/ random-alpha-numeric-string-in-javascript
    RANDOM.randomString = function(len, chars, useChars) {
        var mask, result, i, nSpaces;
        if ('undefined' !== typeof len) {
            if ('number' !== typeof len || len < 1) {
                throw new Error('randomString: len must a number > 0 or ' +
                                'undefined. Found: ' + len);

            }
        }
        if ('undefined' !== typeof chars) {
            if ('string' !== typeof chars || chars.trim() === '') {
                throw new Error('randomString: chars must a non-empty string ' +
                                'or undefined. Found: ' + chars);

            }
        }
        else if (useChars) {
            throw new Error('randomString: useChars is TRUE, but chars ' +
                            'is undefined.');

        }

Defaults.

        len = len || 6;
        chars = chars || 'a';

Create/use mask from chars.

        mask = '';
        if (!useChars) {
            if (chars.indexOf('a') > -1) mask += 'abcdefghijklmnopqrstuvwxyz';
            if (chars.indexOf('A') > -1) mask += 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
            if (chars.indexOf('1') > -1) mask += '0123456789';
            if (chars.indexOf('!') > -1) {
                mask += '!~`@#$%^&*()_+-={}[]:";\'<>?,./|\\';
            }

Check how many spaces we should add.

            nSpaces = chars.indexOf('_');
            if (nSpaces > -1) {
                nSpaces = chars.charAt(nSpaces + 1);

nSpaces is integer > 0 or 1.

                nSpaces = JSUS.isInt(nSpaces, 0) || 1;
                if (nSpaces === 1) mask += ' ';
                else if (nSpaces === 2) mask += '  ';
                else if (nSpaces === 3) mask += '   ';
                else {
                    i = -1;
                    for ( ; ++i < nSpaces ; ) {
                        mask += ' ';
                    }
                }
            }
        }
        else {
            mask = chars;
        }

        i = -1, result = '';
        for ( ; ++i < len ; ) {
            result += mask[Math.floor(Math.random() * mask.length)];
        }
        return result;
    };


    JSUS.extend(RANDOM);

})('undefined' !== typeof JSUS ? JSUS : module.parent.exports.JSUS);