2015-03-19 00:06:26 -04:00

109 lines
3.1 KiB
JavaScript

'use strict';
module.exports = function (math) {
var Matrix = math.type.Matrix,
Unit = require('../../type/Unit'),
BigNumber = math.type.BigNumber,
collection = math.collection,
isNumber = require('../../util/number').isNumber,
isCollection = collection.isCollection,
flatten = require('../../util/array').flatten;
/**
* Compute the median of a matrix or a list with values. The values are
* sorted and the middle value is returned. In case of an even number of
* values, the average of the two middle values is returned.
* Supported types of values are: Number, BigNumber, Unit
*
* In case of a (multi dimensional) array or matrix, the median of all
* elements will be calculated.
*
* Syntax:
*
* math.median(a, b, c, ...)
* math.median(A)
*
* Examples:
*
* math.median(5, 2, 7); // returns 5
* math.median([3, -1, 5, 7]); // returns 4
*
* See also:
*
* mean, min, max, sum, prod, std, var
*
* @param {... *} args A single matrix or or multiple scalar values
* @return {*} The median
*/
math.median = function median(args) {
if (arguments.length == 0) {
throw new SyntaxError('Function median requires one or more parameters (0 provided)');
}
if (isCollection(args)) {
if (arguments.length == 1) {
// median([a, b, c, d, ...])
return _median(args.valueOf());
}
else if (arguments.length == 2) {
// median([a, b, c, d, ...], dim)
// TODO: implement median(A, dim)
throw new Error('median(A, dim) is not yet supported');
//return collection.reduce(arguments[0], arguments[1], ...);
}
else {
throw new SyntaxError('Wrong number of parameters');
}
}
else {
// median(a, b, c, d, ...)
return _median(Array.prototype.slice.call(arguments));
}
};
/**
* Recursively calculate the median of an n-dimensional array
* @param {Array} array
* @return {Number} median
* @private
*/
function _median(array) {
var flat = flatten(array);
flat.sort(math.compare);
var num = flat.length;
if (num == 0) {
throw new Error('Cannot calculate median of an empty array');
}
if (num % 2 == 0) {
// even: return the average of the two middle values
var left = flat[num / 2 - 1];
var right = flat[num / 2];
if (!isNumber(left) && !(left instanceof BigNumber) && !(left instanceof Unit)) {
throw new math.error.UnsupportedTypeError('median', math['typeof'](left));
}
if (!isNumber(right) && !(right instanceof BigNumber) && !(right instanceof Unit)) {
throw new math.error.UnsupportedTypeError('median', math['typeof'](right));
}
return math.divide(math.add(left, right), 2);
}
else {
// odd: return the middle value
var middle = flat[(num - 1) / 2];
if (!isNumber(middle) && !(middle instanceof BigNumber) && !(middle instanceof Unit)) {
throw new math.error.UnsupportedTypeError('median', math['typeof'](middle));
}
return middle;
}
}
};