UNPKG

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.

197 lines (179 loc) 7.54 kB
var BigNumber = require('decimal.js'), isNumber = require('./number').isNumber; digits = require('./number').digits; /** * Test whether value is a BigNumber * @param {*} value * @return {Boolean} isBigNumber */ exports.isBigNumber = function isBigNumber(value) { return (value instanceof BigNumber); }; /** * Convert a number to a formatted string representation. * * Syntax: * * format(value) * format(value, options) * format(value, precision) * format(value, fn) * * Where: * * {Number} value The value to be formatted * {Object} options An object with formatting options. Available options: * {String} notation * Number notation. Choose from: * 'fixed' Always use regular number notation. * For example '123.40' and '14000000' * 'exponential' Always use exponential notation. * For example '1.234e+2' and '1.4e+7' * 'auto' (default) Regular number notation for numbers * having an absolute value between * `lower` and `upper` bounds, and uses * exponential notation elsewhere. * Lower bound is included, upper bound * is excluded. * For example '123.4' and '1.4e7'. * {Number} precision A number between 0 and 16 to round * the digits of the number. * In case of notations 'exponential' and * 'auto', `precision` defines the total * number of significant digits returned * and is undefined by default. * In case of notation 'fixed', * `precision` defines the number of * significant digits after the decimal * point, and is 0 by default. * {Object} exponential An object containing two parameters, * {Number} lower and {Number} upper, * used by notation 'auto' to determine * when to return exponential notation. * Default values are `lower=1e-3` and * `upper=1e5`. * Only applicable for notation `auto`. * {Function} fn A custom formatting function. Can be used to override the * built-in notations. Function `fn` is called with `value` as * parameter and must return a string. Is useful for example to * format all values inside a matrix in a particular way. * * Examples: * * format(6.4); // '6.4' * format(1240000); // '1.24e6' * format(1/3); // '0.3333333333333333' * format(1/3, 3); // '0.333' * format(21385, 2); // '21000' * format(12.071, {notation: 'fixed'}); // '12' * format(2.3, {notation: 'fixed', precision: 2}); // '2.30' * format(52.8, {notation: 'exponential'}); // '5.28e+1' * * @param {BigNumber} value * @param {Object | Function | Number} [options] * @return {String} str The formatted value */ exports.format = function format(value, options) { if (typeof options === 'function') { // handle format(value, fn) return options(value); } // handle special cases if (!value.isFinite()) { return value.isNaN() ? 'NaN' : (value.gt(0) ? 'Infinity' : '-Infinity'); } // default values for options var notation = 'auto'; var precision = undefined; if (options !== undefined) { // determine notation from options if (options.notation) { notation = options.notation; } // determine precision from options if (isNumber(options)) { precision = options; } else if (options.precision) { precision = options.precision; } } // handle the various notations switch (notation) { case 'fixed': return exports.toFixed(value, precision); case 'exponential': return exports.toExponential(value, precision); case 'auto': // determine lower and upper bound for exponential notation. // TODO: implement support for upper and lower to be BigNumbers themselves var lower = 1e-3; var upper = 1e5; if (options && options.exponential) { if (options.exponential.lower !== undefined) { lower = options.exponential.lower; } if (options.exponential.upper !== undefined) { upper = options.exponential.upper; } } // adjust the configuration of the BigNumber constructor (yeah, this is quite tricky...) var oldConfig = { toExpNeg: value.constructor.toExpNeg, toExpPos: value.constructor.toExpPos }; value.constructor.config({ toExpNeg: Math.round(Math.log(lower) / Math.LN10), toExpPos: Math.round(Math.log(upper) / Math.LN10) }); // handle special case zero if (value.isZero()) return '0'; // determine whether or not to output exponential notation var str; var abs = value.abs(); if (abs.gte(lower) && abs.lt(upper)) { // normal number notation str = value.toSignificantDigits(precision).toFixed(); } else { // exponential notation str = exports.toExponential(value, precision); } // remove trailing zeros after the decimal point return str.replace(/((\.\d*?)(0+))($|e)/, function () { var digits = arguments[2]; var e = arguments[4]; return (digits !== '.') ? digits + e : e; }); default: throw new Error('Unknown notation "' + notation + '". ' + 'Choose "auto", "exponential", or "fixed".'); } }; /** * Format a number in exponential notation. Like '1.23e+5', '2.3e+0', '3.500e-3' * @param {BigNumber} value * @param {Number} [precision] Number of digits in formatted output. * If not provided, the maximum available digits * is used. * @returns {string} str */ exports.toExponential = function toExponential (value, precision) { if (precision !== undefined) { return value.toExponential(precision - 1); // Note the offset of one } else { return value.toExponential(); } }; /** * Format a number with fixed notation. * @param {BigNumber} value * @param {Number} [precision=0] Optional number of decimals after the * decimal point. Zero by default. */ exports.toFixed = function toFixed (value, precision) { return value.toFixed(precision || 0); // Note: the (precision || 0) is needed as the toFixed of BigNumber has an // undefined default precision instead of 0. };