Permalink
Browse files

Refactored combinations, factorial, gamma, permutations, pickRandom, …

…random, randomInt to typed-functions
1 parent e1fa9c8 commit 1d5a972a58d9dad9cbd74265ab0bc50498c41b8f @josdejong committed Apr 15, 2015
View
@@ -1,4 +1,3 @@
-_site
coverage
img
misc
View
@@ -153,14 +153,14 @@ function create (config) {
require('./lib/function/matrix/zeros')(math, _config);
// functions - probability
- //require('./lib/function/probability/distribution')(math, _config); // TODO: rethink math.distribution
- require('./lib/function/probability/factorial')(math, _config);
- require('./lib/function/probability/gamma')(math, _config);
- require('./lib/function/probability/random')(math, _config);
- require('./lib/function/probability/randomInt')(math, _config);
- require('./lib/function/probability/pickRandom')(math, _config);
- require('./lib/function/probability/permutations')(math, _config);
- require('./lib/function/probability/combinations')(math, _config);
+ //math.import(require('./lib/function/probability/distribution')); // TODO: rethink math.distribution
+ math.import(require('./lib/function/probability/combinations'));
+ math.import(require('./lib/function/probability/factorial'));
+ math.import(require('./lib/function/probability/gamma'));
+ math.import(require('./lib/function/probability/permutations'));
+ math.import(require('./lib/function/probability/pickRandom'));
+ math.import(require('./lib/function/probability/random'));
+ math.import(require('./lib/function/probability/randomInt'));
// functions - relational
math.import(require('./lib/function/relational/compare'));
@@ -1,14 +1,8 @@
'use strict';
-module.exports = function (math) {
- var util = require('../../util/index'),
-
- BigNumber = math.type.BigNumber,
- collection = math.collection,
-
- isNumber = util.number.isNumber,
- isInteger = util.number.isInteger;
+var isInteger = require('../../util/number').isInteger;
+function factory (type, config, load, typed) {
/**
* Compute the number of ways of picking `k` unordered outcomes from `n`
* possibilities.
@@ -32,17 +26,12 @@ module.exports = function (math) {
* @param {Number | BigNumber} k Number of objects in the subset
* @return {Number | BigNumber} Number of possible combinations.
*/
- math.combinations = function combinations (n, k) {
- var max, result, i,ii;
-
- var arity = arguments.length;
- if (arity != 2) {
- throw new math.error.ArgumentsError('combinations', arguments.length, 2);
- }
+ return typed('combinations', {
+ 'number, number': function (n, k) {
+ var max, result, i;
- if (isNumber(n)) {
if (!isInteger(n) || n < 0) {
- throw new TypeError('Positive integer value enpected in function combinations');
+ throw new TypeError('Positive integer value expected in function combinations');
}
if (k > n) {
throw new TypeError('k must be less than or equal to n');
@@ -53,15 +42,15 @@ module.exports = function (math) {
for (i = 1; i <= n - max; i++) {
result = result * (max + i) / i;
}
+
return result;
- }
+ },
- if (n instanceof BigNumber) {
- // make sure k is a BigNumber as well
- // not all numbers can be converted to BigNumber
- k = BigNumber.convert(k);
+ 'BigNumber, BigNumber': function (n, k) {
+ var max, result, i, ii;
+ var one = new type.BigNumber(1);
- if (!(k instanceof BigNumber) || !isPositiveInteger(n) || !isPositiveInteger(k)) {
+ if (!isPositiveInteger(n) || !isPositiveInteger(k)) {
throw new TypeError('Positive integer value expected in function combinations');
}
if (k.gt(n)) {
@@ -70,22 +59,26 @@ module.exports = function (math) {
max = n.minus(k);
if (k.lt(max)) max = k;
- result = new BigNumber(1);
- for (i = new BigNumber(1), ii = n.minus(max); i.lte(ii); i = i.plus(1)) {
+ result = one;
+ for (i = one, ii = n.minus(max); i.lte(ii); i = i.plus(1)) {
result = result.times(max.plus(i)).dividedBy(i);
}
+
return result;
}
- throw new math.error.UnsupportedTypeError('combinations', math['typeof'](n));
- };
+ // TODO: implement support for collection in combinations
+ });
+}
- /**
- * Test whether BigNumber n is a positive integer
- * @param {BigNumber} n
- * @returns {boolean} isPositiveInteger
- */
- var isPositiveInteger = function(n) {
- return n.isInteger() && n.gte(0);
- };
-};
+/**
+ * Test whether BigNumber n is a positive integer
+ * @param {BigNumber} n
+ * @returns {boolean} isPositiveInteger
+ */
+function isPositiveInteger(n) {
+ return n.isInteger() && n.gte(0);
+}
+
+exports.name = 'combinations';
+exports.factory = factory;
@@ -1,12 +1,14 @@
'use strict';
-// NOTE: distribution is NOT added to math.distribution but returned by the factory function
-// TODO: rethink math.distribution
+var ArgumentsError = require('../../error/ArgumentsError');
-module.exports = function (math) {
- var Matrix = math.type.Matrix;
+// TODO: rethink math.distribution
+// TODO: rework to a typed function
+function factory (type, config, load, typed) {
+ var collection = load(require('../../type/collection'));
+ var matrix = load(require('../construction/matrix'));
var array = require('../../util/array');
- var collection = math.collection;
+
var isCollection = collection.isCollection;
/**
@@ -20,7 +22,7 @@ module.exports = function (math) {
* Examples:
*
* var normalDist = math.distribution('normal'); // create a normal distribution
- * normalDist.random(0, 10); // get a random value between 0 and 10
+ * normalDist.random(0, 10); // get a random value between 0 and 10
*
* See also:
*
@@ -47,7 +49,7 @@ module.exports = function (math) {
random: function(arg1, arg2, arg3) {
var size, min, max;
if (arguments.length > 3) {
- throw new math.error.ArgumentsError('random', arguments.length, 0, 3);
+ throw new ArgumentsError('random', arguments.length, 0, 3);
// `random(max)` or `random(size)`
} else if (arguments.length === 1) {
@@ -80,15 +82,15 @@ module.exports = function (math) {
if (min === undefined) min = 0;
if (size !== undefined) {
var res = _randomDataForMatrix(size.valueOf(), min, max, _random);
- return (size instanceof Matrix) ? math.matrix(res) : res;
+ return (size instanceof type.Matrix) ? matrix(res) : 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);
+ throw new ArgumentsError('randomInt', arguments.length, 1, 3);
// `random(max)` or `random(size)`
else if (arguments.length === 1)
@@ -120,20 +122,20 @@ module.exports = function (math) {
if (min === undefined) min = 0;
if (size !== undefined) {
var res = _randomDataForMatrix(size.valueOf(), min, max, _randomInt);
- return (size instanceof Matrix) ? math.matrix(res) : res;
+ return (size instanceof type.Matrix) ? matrix(res) : res;
}
else return _randomInt(min, max);
},
pickRandom: function(possibles) {
if (arguments.length !== 1) {
- throw new math.error.ArgumentsError('pickRandom', arguments.length, 1);
+ throw new ArgumentsError('pickRandom', arguments.length, 1);
}
- if (possibles instanceof Matrix) {
+ if (possibles instanceof type.Matrix) {
possibles = possibles.valueOf(); // get Array
}
else if (!Array.isArray(possibles)) {
- throw new math.error.UnsupportedTypeError('pickRandom', math['typeof'](possibles));
+ throw new TypeError('Unsupported type of value in function pickRandom');
}
if (array.size(possibles).length > 1) {
@@ -173,7 +175,7 @@ module.exports = function (math) {
return randFunctions;
})(distribution);
- };
+ }
// Each distribution is a function that takes no argument and when called returns
// a number between 0 and 1.
@@ -204,4 +206,7 @@ module.exports = function (math) {
};
return distribution;
-};
+}
+
+exports.name = 'distribution';
+exports.factory = factory;
@@ -1,15 +1,10 @@
'use strict';
-module.exports = function (math, config) {
- var util = require('../../util/index'),
+var bignumber = require('../../util/bignumber');
- BigNumber = math.type.BigNumber,
- collection = math.collection,
-
- isNumber = util.number.isNumber,
- isBoolean = util['boolean'].isBoolean,
- isInteger = util.number.isInteger,
- isCollection = collection.isCollection;
+function factory (type, config, load, typed) {
+ var collection = load(require('../../type/collection'));
+ var gamma = load(require('./gamma'));
/**
* Compute the factorial of a value
@@ -33,104 +28,30 @@ module.exports = function (math, config) {
* @param {Number | BigNumber | Array | Matrix | Boolean | null} n An integer number
* @return {Number | BigNumber | Array | Matrix} The factorial of `n`
*/
- math.factorial = function factorial (n) {
- var value, res, preciseFacs;
-
- if (arguments.length != 1) {
- throw new math.error.ArgumentsError('factorial', arguments.length, 1);
- }
-
- if (isNumber(n)) {
- return n !== Number.POSITIVE_INFINITY
- ? math.gamma(n + 1)
- : Math.sqrt(2*Math.PI);
- }
-
- if (n instanceof BigNumber) {
- if (!(isNonNegativeInteger(n))) {
- return n.isNegative() || n.isFinite()
- ? math.gamma(n.plus(1))
- : util.bignumber.tau(config.precision).sqrt();
- }
-
- n = n.toNumber(); // should definitely be below Number.MAX_VALUE
- if (n < smallBigFacs.length) {
- return BigNumber.convert(smallBigFacs[n]).toSD(config.precision);
+ var factorial = typed('factorial', {
+ 'number': function (n) {
+ if (n === Number.POSITIVE_INFINITY) {
+ return Math.sqrt(2 * Math.PI);
}
- // be wary of round-off errors
- var precision = config.precision + (Math.log(n) | 0);
- var Big = BigNumber.constructor({precision: precision});
+ return gamma(n + 1);
+ },
- // adjust n do align with the precision specific tables
- n -= smallBigFacs.length;
- if (preciseFacs = bigBigFacs[precision]) {
- if (preciseFacs[n]) {
- return new BigNumber(preciseFacs[n].toPrecision(config.precision));
- }
- res = preciseFacs[preciseFacs.length-1];
- } else {
- preciseFacs = bigBigFacs[precision] = [];
- res = new Big(smallBigFacs[smallBigFacs.length-1])
- .toSD(precision);
+ 'BigNumber': function (n) {
+ if (!n.isFinite() && !n.isNegative()) {
+ return bignumber.tau(config.precision).sqrt();
}
- var one = new Big(1);
- value = new Big(preciseFacs.length + smallBigFacs.length);
- for (var i = preciseFacs.length; i < n; ++i) {
- preciseFacs[i] = res = res.times(value);
- value = value.plus(one);
- }
+ return gamma(n.plus(1));
+ },
- preciseFacs[n] = res.times(value);
- return new BigNumber(preciseFacs[n].toPrecision(config.precision));
- }
-
- if (isBoolean(n) || n === null) {
- return 1; // factorial(1) = 1, factorial(0) = 1
- }
-
- if (isCollection(n)) {
+ 'Array | Matrix': function (n) {
return collection.deepMap(n, factorial);
}
+ });
- throw new math.error.UnsupportedTypeError('factorial', math['typeof'](n));
- };
-
- /**
- * Test whether BigNumber n is a non-negative integer
- * @param {BigNumber} n
- * @returns {boolean} isNonNegativeInteger
- */
- var isNonNegativeInteger = function(n) {
- return n.isInteger() && (!n.isNegative() || n.isZero());
- };
-
- // 21! >= values for each precision
- var bigBigFacs = [];
+ return factorial;
+}
- // 0-20! values
- var smallBigFacs = [
- 1,
- 1,
- 2,
- 6,
- 24,
- 120,
- 720,
- 5040,
- 40320,
- 362880,
- 3628800,
- 39916800,
- 479001600,
- 6227020800,
- 87178291200,
- 1307674368000,
- 20922789888000,
- 355687428096000,
- 6402373705728000,
- 121645100408832000,
- 2432902008176640000
- ]
-};
+exports.name = 'factorial';
+exports.factory = factory;
Oops, something went wrong.

0 comments on commit 1d5a972

Please sign in to comment.