UNPKG

mathjs

Version:

Math.js is an extensive math library for JavaScript and Node.js. It features a flexible expression parser and offers an integrated solution to work with numbers, big numbers, complex numbers, units, and matrices.

180 lines (152 loc) 5.77 kB
module.exports = function (math, config) { var Matrix = require('../../type/Matrix'), collection = require('../../type/collection'); // TODO: implement BigNumber support for random /** * Return a random number between 0 and 1 * * random() * * @return {Number} res */ // Each distribution is a function that takes no argument and when called returns // a number between 0 and 1. var distributions = { uniform: function() { return Math.random; }, // Implementation of normal distribution using Box-Muller transform // ref : http://en.wikipedia.org/wiki/Box%E2%80%93Muller_transform // We take : mean = 0.5, standard deviation = 1/6 // so that 99.7% values are in [0, 1]. normal: function() { return function() { var u1, u2, picked = -1; // We reject values outside of the interval [0, 1] // TODO: check if it is ok to do that? while (picked < 0 || picked > 1) { u1 = Math.random(); u2 = Math.random(); picked = 1/6 * Math.pow(-2 * Math.log(u1), 0.5) * Math.cos(2 * Math.PI * u2) + 0.5; } return picked; } } }; /** * Create a distribution object. * @param {String} name Name of a distribution. * Choose from 'uniform', 'normal'. * @return {Object} distribution A distribution object containing functions: * random([size, min, max]) * randomInt([min, max]) * pickRandom(array) */ math.distribution = function(name) { if (!distributions.hasOwnProperty(name)) throw new Error('unknown distribution ' + name); var args = Array.prototype.slice.call(arguments, 1), distribution = distributions[name].apply(this, args); return (function(distribution) { // This is the public API for all distributions var randFunctions = { random: function(arg1, arg2, arg3) { var size, min, max; if (arguments.length > 3) { throw new math.error.ArgumentsError('random', arguments.length, 0, 3); // `random(max)` or `random(size)` } else if (arguments.length === 1) { if (Array.isArray(arg1)) size = arg1; else max = arg1; // `random(min, max)` or `random(size, max)` } else if (arguments.length === 2) { if (Array.isArray(arg1)) size = arg1; else { min = arg1; max = arg2; } // `random(size, min, max)` } else { size = arg1; min = arg2; max = arg3; } if (max === undefined) max = 1; if (min === undefined) min = 0; if (size !== undefined) { var res = _randomDataForMatrix(size, min, max, _random); return (config.matrix === 'array') ? res : new Matrix(res); } else return _random(min, max); }, randomInt: function(arg1, arg2, arg3) { var size, min, max; if (arguments.length > 3 || arguments.length < 1) throw new math.error.ArgumentsError('randomInt', arguments.length, 1, 3); // `randomInt(max)` else if (arguments.length === 1) max = arg1; // `randomInt(min, max)` or `randomInt(size, max)` else if (arguments.length === 2) { if (Object.prototype.toString.call(arg1) === '[object Array]') size = arg1; else { min = arg1; max = arg2; } // `randomInt(size, min, max)` } else { size = arg1; min = arg2; max = arg3; } if (min === undefined) min = 0; if (size !== undefined) { var res = _randomDataForMatrix(size, min, max, _randomInt); return (config.matrix === 'array') ? res : new Matrix(res); } else return _randomInt(min, max); }, pickRandom: function(possibles) { if (arguments.length !== 1) { throw new math.error.ArgumentsError('pickRandom', arguments.length, 1); } if (!Array.isArray(possibles)) { throw new math.error.UnsupportedTypeError('pickRandom', math['typeof'](possibles)); } // TODO: add support for matrices return possibles[Math.floor(Math.random() * possibles.length)]; } }; var _random = function(min, max) { return min + distribution() * (max - min); }; var _randomInt = function(min, max) { return Math.floor(min + distribution() * (max - min)); }; // This is a function for generating a random matrix recursively. var _randomDataForMatrix = function(size, min, max, randFunc) { var data = [], length, i; size = size.slice(0); if (size.length > 1) { for (i = 0, length = size.shift(); i < length; i++) data.push(_randomDataForMatrix(size, min, max, randFunc)); } else { for (i = 0, length = size.shift(); i < length; i++) data.push(randFunc(min, max)); } return data; }; return randFunctions; })(distribution); }; // Default random functions use uniform distribution // TODO: put random functions in separate files? var uniformRandFunctions = math.distribution('uniform'); math.random = uniformRandFunctions.random; math.randomInt = uniformRandFunctions.randomInt; math.pickRandom = uniformRandFunctions.pickRandom; };