mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
235 lines
7.0 KiB
JavaScript
235 lines
7.0 KiB
JavaScript
var object = require('./lib/util/object');
|
|
var digits = require('./lib/util/number').digits;
|
|
|
|
/**
|
|
* Math.js loader. Creates a new, empty math.js instance
|
|
* @returns {Object} Returns a math.js instance containing
|
|
* a function `import` to add new functions
|
|
*/
|
|
exports.create = function create () {
|
|
// simple test for ES5 support
|
|
if (typeof Object.create !== 'function') {
|
|
throw new Error('ES5 not supported by this JavaScript engine. ' +
|
|
'Please load the es5-shim and es5-sham library for compatibility.');
|
|
}
|
|
|
|
// cached factories and instances
|
|
var factories = [];
|
|
var instances = [];
|
|
|
|
// create a namespace for the mathjs instance
|
|
var math = {
|
|
type: {}
|
|
};
|
|
|
|
var typed = require('typed-function');
|
|
// TODO: must create a separate instance of typed, with custom config.
|
|
// TODO: typed-function must be able to silently ignore signatures with unknown data types
|
|
|
|
// create configuration options. These are private
|
|
var _config = {
|
|
// type of default matrix output. Choose 'matrix' (default) or 'array'
|
|
matrix: 'matrix',
|
|
|
|
// type of default number output. Choose 'number' (default) or 'bignumber'
|
|
number: 'number',
|
|
|
|
// number of significant digits in BigNumbers
|
|
precision: 64,
|
|
|
|
// minimum relative difference between two compared values,
|
|
// used by all comparison functions
|
|
epsilon: 1e-14
|
|
};
|
|
|
|
/**
|
|
* Load a function or data type from a factory.
|
|
* If the function or data type already exists, the existing instance is
|
|
* returned.
|
|
* @param {{type: string, name: string, factory: function}} factory
|
|
* @returns {*}
|
|
*/
|
|
function load (factory) {
|
|
if (!object.isFactory(factory)) {
|
|
throw new Error('Factory object with properties `type`, `name`, and `factory` expected');
|
|
}
|
|
|
|
var index = factories.indexOf(factory);
|
|
var instance;
|
|
if (index === -1) {
|
|
// doesn't yet exist
|
|
if (factory.math) {
|
|
// pass math namespace
|
|
instance = factory.factory(math.type, _config, load, typed, math);
|
|
}
|
|
else {
|
|
instance = factory.factory(math.type, _config, load, typed);
|
|
}
|
|
|
|
// append to the cache
|
|
factories.push(factory);
|
|
instances.push(instance);
|
|
}
|
|
else {
|
|
// already existing function, return this instance
|
|
instance = instances[index];
|
|
}
|
|
|
|
return instance;
|
|
}
|
|
|
|
// load the import function, which can be used to load all other functions,
|
|
// constants, and types
|
|
math['import'] = load(require('./lib/function/utils/import'));
|
|
|
|
// TODO: dynamically load data types into the loader, via factory functions for types
|
|
var Complex = require('./lib/type/Complex');
|
|
var Range = require('./lib/type/Range');
|
|
var Index = require('./lib/type/Index');
|
|
var Matrix = require('./lib/type/Matrix');
|
|
var Unit = require('./lib/type/Unit');
|
|
var Help = require('./lib/type/Help');
|
|
var ResultSet = require('./lib/type/ResultSet');
|
|
var BigNumber = math.import(require('./lib/type/BigNumber'));
|
|
|
|
// types (Matrix, Complex, Unit, ...)
|
|
math.type.Complex = Complex;
|
|
math.type.Range = Range;
|
|
math.type.Index = Index;
|
|
math.type.Matrix = Matrix;
|
|
math.type.Unit = Unit;
|
|
math.type.Help = Help;
|
|
math.type.ResultSet = ResultSet;
|
|
|
|
// configure typed functions
|
|
typed.types['Complex'] = function (x) { return x instanceof Complex; };
|
|
typed.types['Range'] = function (x) { return x instanceof Range; };
|
|
typed.types['Index'] = function (x) { return x instanceof Index; };
|
|
typed.types['Matrix'] = function (x) { return x instanceof Matrix; };
|
|
typed.types['Unit'] = function (x) { return x instanceof Unit; };
|
|
typed.types['Help'] = function (x) { return x instanceof Help; };
|
|
typed.types['ResultSet'] = function (x) { return x instanceof ResultSet; };
|
|
typed.types['BigNumber'] = function (x) { return x instanceof BigNumber; };
|
|
|
|
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 BigNumber(x);
|
|
}
|
|
}, {
|
|
from: 'number',
|
|
to: 'Complex',
|
|
convert: function (x) {
|
|
return new Complex(x, 0);
|
|
}
|
|
}, {
|
|
from: 'number',
|
|
to: 'string',
|
|
convert: function (x) {
|
|
return x + '';
|
|
}
|
|
}, {
|
|
from: 'BigNumber',
|
|
to: 'Complex',
|
|
convert: function (x) {
|
|
return new Complex(x.toNumber(), 0);
|
|
}
|
|
}, {
|
|
from: 'boolean',
|
|
to: 'number',
|
|
convert: function (x) {
|
|
return +x;
|
|
}
|
|
}, {
|
|
from: 'boolean',
|
|
to: 'BigNumber',
|
|
convert: function (x) {
|
|
return new BigNumber(+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 BigNumber(0);
|
|
}
|
|
}, {
|
|
from: 'Array',
|
|
to: 'Matrix',
|
|
convert: function (array) {
|
|
return new Matrix(array);
|
|
}
|
|
}
|
|
];
|
|
|
|
// FIXME: load constants via math.import() like all functions (problem: it must be reloaded when config changes)
|
|
// constants
|
|
require('./lib/constants')(math, _config);
|
|
|
|
/**
|
|
* Set configuration options for math.js, and get current options
|
|
* @param {Object} [options] Available options:
|
|
* {String} matrix
|
|
* A string 'matrix' (default) or 'array'.
|
|
* {String} number
|
|
* A string 'number' (default) or 'bignumber'
|
|
* {Number} precision
|
|
* The number of significant digits for BigNumbers.
|
|
* Not applicable for Numbers.
|
|
* @return {Object} Returns the current configuration
|
|
*/
|
|
// TODO: change the function config into a regular function, move it to /lib/function/utils
|
|
math.config = function config(options) {
|
|
if (options) {
|
|
// merge options
|
|
object.deepExtend(_config, options);
|
|
|
|
if (options.precision) {
|
|
BigNumber.config({
|
|
precision: options.precision
|
|
});
|
|
}
|
|
|
|
// reload the constants (they depend on option number and precision)
|
|
// this must be done after math.type.BigNumber.config is applied
|
|
require('./lib/constants')(math, _config);
|
|
}
|
|
|
|
// return a clone of the settings
|
|
return object.clone(_config);
|
|
};
|
|
|
|
math._config = _config; // TODO: cleanup when everything is converted
|
|
|
|
// TODO: remove errors from the namespace as soon as they are redundant
|
|
// errors
|
|
math.error = require('./lib/error/index');
|
|
|
|
return math;
|
|
};
|