math-tools
Version:
MathTools - is a javascript/node.js module providing some advanced mathematics functionalities
321 lines (296 loc) • 7.22 kB
JavaScript
var mathTools = {};
var NUMBER_ERROR = 'Input must be of type Number';
var ARRAY_ERROR = 'Input must be of type Array';
var FUNCTION_ERROR = 'Input must be of type Function';
var INTEGER_ERROR = 'Input must be of type Integer';
var NUMBER_ARRAY_ERROR = 'All elements in array must be numbers or objects with numbers for given property';
var EPSILON = 1e-10;
mathTools.isNumber = function(value) {
return typeof value === 'number';
};
mathTools.isArray = function(value) {
return value instanceof Array;
};
mathTools.isObject = function(value) {
return typeof value === 'object';
};
mathTools.isFunction = function(value) {
var getType = {};
return value && getType.toString.call(value) === '[object Function]';
};
mathTools.isInteger = function(value) {
if (value === Infinity || value === -Infinity) {
return false;
} else {
return value == Math.round(value);
}
};
var doOperation = function(operator, arr, key) {
if (mathTools.isArray(arr)) {
if (!arr[0]) {
return 0;
}
if (mathTools.isNumber(arr[0])) {
switch (operator) {
case 'addition':
var total = 0;
var i = 0;
break;
default:
var total = arr[0];
var i = 1;
break;
}
for (i; i < arr.length; i++) {
if (mathTools.isNumber(arr[i])) {
switch (operator) {
case 'addition':
total += arr[i];
break;
case 'subtraction':
total -= arr[i];
break;
case 'multiplication':
total = total * arr[i];
break;
}
} else {
throw new Error(NUMBER_ARRAY_ERROR);
}
}
} else if (mathTools.isObject(arr[0])) {
var key = key || 'value';
switch (operator) {
case 'addition':
var total = 0;
var i = 0;
break;
default:
var total = 0;
var i = 0;
for ( var j = 0; j < arr.length; j++) {
if (!mathTools.isObject(arr[i])) {
throw new Error(NUMBER_ARRAY_ERROR);
}
if (arr[j].hasOwnProperty(key)) {
total = arr[j][key];
i = j+1;
break;
}
}
break;
}
for (i; i < arr.length; i++) {
if (!mathTools.isObject(arr[i])) {
throw new Error(NUMBER_ARRAY_ERROR);
}
if (arr[i].hasOwnProperty(key)) {
if (mathTools.isNumber(arr[i][key])) {
switch (operator) {
case 'addition':
total += arr[i][key];
break;
case 'subtraction':
total -= arr[i][key];
break;
case 'multiplication':
total = total * arr[i][key];
break;
}
} else {
throw new Error(NUMBER_ARRAY_ERROR);
}
}
}
} else {
throw new Error(NUMBER_ARRAY_ERROR);
}
return total;
} else {
throw new Error(ARRAY_ERROR);
}
};
/**
* Sum of array
*
* mathTools.sum([1,2,3]) => 6
*
* mathTools.sum([{a: 1},{b: 2},{a: 3}], 'a') => 4
*/
mathTools.sum = function(arr, key) {
return doOperation('addition', arr, key);
};
/**
* Subtraction of array
*
* mathTools.subtraction([1,2,3]) => -4
*
* mathTools.subtraction([{a: 1},{b: 2},{a: 3}], 'a') => -2
*/
mathTools.subtraction = function(arr, key) {
return doOperation('subtraction', arr, key);
};
/**
* Product of array
*
* mathTools.product([1,2,3]) => 6
*
* mathTools.product([{a: 1},{b: 2},{a: 3}], 'a') => 3
*/
mathTools.product = function(arr, key) {
return doOperation('multiplication', arr, key);
};
mathTools.factorial = function(n) {
if (!mathTools.isNumber(n)) {
throw new Error(NUMBER_ERROR);
}
if (n == 0) {
return 1;
} else {
return n * mathTools.factorial(n - 1);
}
};
mathTools.fibonacci = function(n) {
if (!mathTools.isNumber(n)) {
throw new Error(NUMBER_ERROR);
}
n = n > 92 ? 92 : n;
var fib = [];
if (n > 0) {
if (n === 1) {
fib.push(0);
} else {
fib = [ 0, 1 ];
for ( var i = 2; i < n; i++) {
fib[i] = fib[i - 2] + fib[i - 1];
}
}
}
return fib;
};
/**
* Calculate the greastest common divisor amongst two integers.
*/
mathTools.gcd = function(a, b) {
if (!mathTools.isNumber(a) || !mathTools.isNumber(b)) {
throw new Error(NUMBER_ERROR);
}
var c;
a = +a;
b = +b;
if (a !== a || b !== b) {
return NaN;
}
if (a === Infinity || a === -Infinity || b === Infinity || b === -Infinity) {
return Infinity;
}
if ((a % 1 !== 0) || (b % 1 !== 0)) {
throw new Error("Can only operate on integers");
}
while (b) {
c = a % b;
a = b;
b = c;
}
return (0 < a) ? a : -a;
};
/**
* Calculate the least common multiple amongst two integers.
*/
mathTools.lcm = function(a, b) {
if (!mathTools.isNumber(a) || !mathTools.isNumber(b)) {
throw new Error(NUMBER_ERROR);
}
return Math.abs(a * b) / mathTools.gcd(a, b);
};
/**
* Determine if number is prime.
*/
mathTools.isPrime = function(n) {
if (!mathTools.isNumber(n)) {
throw new Error(NUMBER_ERROR);
}
if (isNaN(n) || !isFinite(n) || n % 1 || n < 2) {
return false;
}
if (n % 2 === 0) {
return (n === 2);
}
if (n % 3 === 0) {
return (n === 3);
}
for ( var i = 5, m = Math.sqrt(n); i <= m; i += 6) {
if ((n % i === 0) || (n % (i + 2) === 0)) {
return false;
}
}
return true;
};
/**
* Average of array
*/
mathTools.avg = function(arr) {
if (mathTools.isArray(arr)) {
var length = arr.length;
return mathTools.sum(arr) / length;
} else {
throw new Error(ARRAY_ERROR);
}
};
/**
* Find the standard deviation of a set of numbers.
*/
mathTools.standardDeviation = function(arr) {
var avg = mathTools.avg(arr);
var length = arr.length;
var squareSum = 0;
for ( var i = 0; i < length; i++) {
squareSum += Math.pow((arr[i] - avg), 2);
}
return Math.sqrt(squareSum / length);
};
/**
* Calculate integral of a function from a to b using adaptive simpson
* quadrature.
*/
mathTools.adaptiveSimpsonQuadrature = function(func, a, b) {
if (!mathTools.isFunction(func)) {
throw new Error(FUNCTION_ERROR);
}
if (!mathTools.isInteger(a) || !mathTools.isInteger(b)) {
throw new Error(INTEGER_ERROR);
}
var h = b - a;
var c = (a + b) / 2.0;
var d = (a + c) / 2.0;
var e = (b + c) / 2.0;
var left = h / 6 * (func(a) + 4 * func(c) + func(b));
var right = h / 12
* (func(a) + 4 * func(d) + 2 * func(c) + 4 * func(e) + func(b));
if (Math.abs(right - left) <= EPSILON) {
return right + (right - left) / 15;
} else {
return mathTools.adaptiveSimpsonQuadrature(a, c)
+ mathTools.adaptiveSimpsonQuadrature(c, b);
}
};
/**
* Calculate integral of a function from a to b using Trapezoidal rule.
*/
mathTools.trapezoidal = function(func, a, b, subintervals) {
if (!mathTools.isFunction(func)) {
throw new Error(FUNCTION_ERROR);
}
subintervals = subintervals || 200;
if (!mathTools.isInteger(a) || !mathTools.isInteger(b)
|| !mathTools.isInteger(subintervals)) {
throw new Error(INTEGER_ERROR);
}
var h = (b - a) / subintervals;
var sum = 0.5 * h * (func(a) + func(b));
for ( var k = 1; k < subintervals; k++) {
sum = sum + h * func(a + h * k);
}
return sum;
};
module.exports = mathTools;