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.
183 lines (176 loc) • 6.08 kB
JavaScript
var typedFunction = require('typed-function');
var digits = require('./../utils/number').digits;
// returns a new instance of typed-function
var createTyped = function () {
// initially, return the original instance of typed-function
// consecutively, return a new instance from typed.create.
createTyped = typedFunction.create;
return typedFunction;
};
/**
* Factory function for creating a new typed instance
* @param {Object} type Object with data types like Complex and BigNumber
* @returns {Function}
*/
exports.create = function create(type) {
// TODO: typed-function must be able to silently ignore signatures with unknown data types
// get a new instance of typed-function
var typed = createTyped();
// define all types. The order of the types determines in which order function
// arguments are type-checked (so for performance it's important to put the
// most used types first).
typed.types = [
{ name: 'number', test: function (x) { return typeof x === 'number'; } },
{ name: 'Complex', test: function (x) { return x && x.isComplex; } },
{ name: 'BigNumber', test: function (x) { return x && x.isBigNumber; } },
{ name: 'Fraction', test: function (x) { return x && x.isFraction; } },
{ name: 'Unit', test: function (x) { return x && x.isUnit; } },
{ name: 'string', test: function (x) { return typeof x === 'string'; } },
{ name: 'Array', test: Array.isArray },
{ name: 'Matrix', test: function (x) { return x && x.isMatrix; } },
{ name: 'DenseMatrix', test: function (x) { return x && x.isDenseMatrix; } },
{ name: 'SparseMatrix', test: function (x) { return x && x.isSparseMatrix; } },
{ name: 'ImmutableDenseMatrix', test: function (x) { return x && x.isImmutableDenseMatrix; } },
{ name: 'Range', test: function (x) { return x && x.isRange; } },
{ name: 'Index', test: function (x) { return x && x.isIndex; } },
{ name: 'boolean', test: function (x) { return typeof x === 'boolean'; } },
{ name: 'ResultSet', test: function (x) { return x && x.isResultSet; } },
{ name: 'Help', test: function (x) { return x && x.isHelp; } },
{ name: 'function', test: function (x) { return typeof x === 'function';} },
{ name: 'Date', test: function (x) { return x instanceof Date; } },
{ name: 'RegExp', test: function (x) { return x instanceof RegExp; } },
{ name: 'Object', test: function (x) { return typeof x === 'object'; } },
{ name: 'null', test: function (x) { return x === null; } },
{ name: 'undefined', test: function (x) { return x === undefined; } }
];
// TODO: add conversion from BigNumber to number?
typed.conversions = [
{
from: 'number',
to: 'BigNumber',
convert: function (x) {
// note: conversion from number to BigNumber can fail if x has >15 digits
if (digits(x) > 15) {
throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' +
'(value: ' + x + '). ' +
'Use function bignumber(x) to convert to BigNumber.');
}
return new type.BigNumber(x);
}
}, {
from: 'number',
to: 'Complex',
convert: function (x) {
return new type.Complex(x, 0);
}
}, {
from: 'number',
to: 'string',
convert: function (x) {
return x + '';
}
}, {
from: 'BigNumber',
to: 'Complex',
convert: function (x) {
return new type.Complex(x.toNumber(), 0);
}
}, {
from: 'Fraction',
to: 'Complex',
convert: function (x) {
return new type.Complex(x.valueOf(), 0);
}
}, {
from: 'number',
to: 'Fraction',
convert: function (x) {
if (digits(x) > 15) {
throw new TypeError('Cannot implicitly convert a number with >15 significant digits to Fraction ' +
'(value: ' + x + '). ' +
'Use function fraction(x) to convert to Fraction.');
}
return new type.Fraction(x);
}
}, {
// FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))`
// from: 'Fraction',
// to: 'number',
// convert: function (x) {
// return x.valueOf();
// }
//}, {
from: 'string',
to: 'number',
convert: function (x) {
var n = Number(x);
if (isNaN(n)) {
throw new Error('Cannot convert "' + x + '" to a number');
}
return n;
}
}, {
from: 'boolean',
to: 'number',
convert: function (x) {
return +x;
}
}, {
from: 'boolean',
to: 'BigNumber',
convert: function (x) {
return new type.BigNumber(+x);
}
}, {
from: 'boolean',
to: 'Fraction',
convert: function (x) {
return new type.Fraction(+x);
}
}, {
from: 'boolean',
to: 'string',
convert: function (x) {
return +x;
}
}, {
from: 'null',
to: 'number',
convert: function () {
return 0;
}
}, {
from: 'null',
to: 'string',
convert: function () {
return 'null';
}
}, {
from: 'null',
to: 'BigNumber',
convert: function () {
return new type.BigNumber(0);
}
}, {
from: 'null',
to: 'Fraction',
convert: function () {
return new type.Fraction(0);
}
}, {
from: 'Array',
to: 'Matrix',
convert: function (array) {
// TODO: how to decide on the right type of matrix to create?
return new type.DenseMatrix(array);
}
}, {
from: 'Matrix',
to: 'Array',
convert: function (matrix) {
return matrix.valueOf();
}
}
];
return typed;
};