var error = require('./utils/error'); var jStat = require('jstat'); var text = require('./text'); var utils = require('./utils/common'); var bessel = require('bessel'); function isValidBinaryNumber(number) { return (/^[01]{1,10}$/).test(number); } exports.BESSELI = function(x, n) { x = utils.parseNumber(x); n = utils.parseNumber(n); if (utils.anyIsError(x, n)) { return error.value; } return bessel.besseli(x, n); }; exports.BESSELJ = function(x, n) { x = utils.parseNumber(x); n = utils.parseNumber(n); if (utils.anyIsError(x, n)) { return error.value; } return bessel.besselj(x, n); }; exports.BESSELK = function(x, n) { x = utils.parseNumber(x); n = utils.parseNumber(n); if (utils.anyIsError(x, n)) { return error.value; } return bessel.besselk(x, n); }; exports.BESSELY = function(x, n) { x = utils.parseNumber(x); n = utils.parseNumber(n); if (utils.anyIsError(x, n)) { return error.value; } return bessel.bessely(x, n); }; exports.BIN2DEC = function(number) { // Return error if number is not binary or contains more than 10 characters (10 digits) if (!isValidBinaryNumber(number)) { return error.num; } // Convert binary number to decimal var result = parseInt(number, 2); // Handle negative numbers var stringified = number.toString(); if (stringified.length === 10 && stringified.substring(0, 1) === '1') { return parseInt(stringified.substring(1), 2) - 512; } else { return result; } }; exports.BIN2HEX = function(number, places) { // Return error if number is not binary or contains more than 10 characters (10 digits) if (!isValidBinaryNumber(number)) { return error.num; } // Ignore places and return a 10-character hexadecimal number if number is negative var stringified = number.toString(); if (stringified.length === 10 && stringified.substring(0, 1) === '1') { return (1099511627264 + parseInt(stringified.substring(1), 2)).toString(16); } // Convert binary number to hexadecimal var result = parseInt(number, 2).toString(16); // Return hexadecimal number using the minimum number of characters necessary if places is undefined if (places === undefined) { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.BIN2OCT = function(number, places) { // Return error if number is not binary or contains more than 10 characters (10 digits) if (!isValidBinaryNumber(number)) { return error.num; } // Ignore places and return a 10-character octal number if number is negative var stringified = number.toString(); if (stringified.length === 10 && stringified.substring(0, 1) === '1') { return (1073741312 + parseInt(stringified.substring(1), 2)).toString(8); } // Convert binary number to octal var result = parseInt(number, 2).toString(8); // Return octal number using the minimum number of characters necessary if places is undefined if (places === undefined) { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.BITAND = function(number1, number2) { // Return error if either number is a non-numeric value number1 = utils.parseNumber(number1); number2 = utils.parseNumber(number2); if (utils.anyIsError(number1, number2)) { return error.value; } // Return error if either number is less than 0 if (number1 < 0 || number2 < 0) { return error.num; } // Return error if either number is a non-integer if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) { return error.num; } // Return error if either number is greater than (2^48)-1 if (number1 > 281474976710655 || number2 > 281474976710655) { return error.num; } // Return bitwise AND of two numbers return number1 & number2; }; exports.BITLSHIFT = function(number, shift) { number = utils.parseNumber(number); shift = utils.parseNumber(shift); if (utils.anyIsError(number, shift)) { return error.value; } // Return error if number is less than 0 if (number < 0) { return error.num; } // Return error if number is a non-integer if (Math.floor(number) !== number) { return error.num; } // Return error if number is greater than (2^48)-1 if (number > 281474976710655) { return error.num; } // Return error if the absolute value of shift is greater than 53 if (Math.abs(shift) > 53) { return error.num; } // Return number shifted by shift bits to the left or to the right if shift is negative return (shift >= 0) ? number << shift : number >> -shift; }; exports.BITOR = function(number1, number2) { number1 = utils.parseNumber(number1); number2 = utils.parseNumber(number2); if (utils.anyIsError(number1, number2)) { return error.value; } // Return error if either number is less than 0 if (number1 < 0 || number2 < 0) { return error.num; } // Return error if either number is a non-integer if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) { return error.num; } // Return error if either number is greater than (2^48)-1 if (number1 > 281474976710655 || number2 > 281474976710655) { return error.num; } // Return bitwise OR of two numbers return number1 | number2; }; exports.BITRSHIFT = function(number, shift) { number = utils.parseNumber(number); shift = utils.parseNumber(shift); if (utils.anyIsError(number, shift)) { return error.value; } // Return error if number is less than 0 if (number < 0) { return error.num; } // Return error if number is a non-integer if (Math.floor(number) !== number) { return error.num; } // Return error if number is greater than (2^48)-1 if (number > 281474976710655) { return error.num; } // Return error if the absolute value of shift is greater than 53 if (Math.abs(shift) > 53) { return error.num; } // Return number shifted by shift bits to the right or to the left if shift is negative return (shift >= 0) ? number >> shift : number << -shift; }; exports.BITXOR = function(number1, number2) { number1 = utils.parseNumber(number1); number2 = utils.parseNumber(number2); if (utils.anyIsError(number1, number2)) { return error.value; } // Return error if either number is less than 0 if (number1 < 0 || number2 < 0) { return error.num; } // Return error if either number is a non-integer if (Math.floor(number1) !== number1 || Math.floor(number2) !== number2) { return error.num; } // Return error if either number is greater than (2^48)-1 if (number1 > 281474976710655 || number2 > 281474976710655) { return error.num; } // Return bitwise XOR of two numbers return number1 ^ number2; }; exports.COMPLEX = function(real, imaginary, suffix) { real = utils.parseNumber(real); imaginary = utils.parseNumber(imaginary); if (utils.anyIsError(real, imaginary)) { return real; } // Set suffix suffix = (suffix === undefined) ? 'i' : suffix; // Return error if suffix is neither "i" nor "j" if (suffix !== 'i' && suffix !== 'j') { return error.value; } // Return complex number if (real === 0 && imaginary === 0) { return 0; } else if (real === 0) { return (imaginary === 1) ? suffix : imaginary.toString() + suffix; } else if (imaginary === 0) { return real.toString(); } else { var sign = (imaginary > 0) ? '+' : ''; return real.toString() + sign + ((imaginary === 1) ? suffix : imaginary.toString() + suffix); } }; exports.CONVERT = function(number, from_unit, to_unit) { number = utils.parseNumber(number); if (number instanceof Error) { return number; } // List of units supported by CONVERT and units defined by the International System of Units // [Name, Symbol, Alternate symbols, Quantity, ISU, CONVERT, Conversion ratio] var units = [ ["a.u. of action", "?", null, "action", false, false, 1.05457168181818e-34], ["a.u. of charge", "e", null, "electric_charge", false, false, 1.60217653141414e-19], ["a.u. of energy", "Eh", null, "energy", false, false, 4.35974417757576e-18], ["a.u. of length", "a?", null, "length", false, false, 5.29177210818182e-11], ["a.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31], ["a.u. of time", "?/Eh", null, "time", false, false, 2.41888432650516e-17], ["admiralty knot", "admkn", null, "speed", false, true, 0.514773333], ["ampere", "A", null, "electric_current", true, false, 1], ["ampere per meter", "A/m", null, "magnetic_field_intensity", true, false, 1], ["ångström", "Å", ["ang"], "length", false, true, 1e-10], ["are", "ar", null, "area", false, true, 100], ["astronomical unit", "ua", null, "length", false, false, 1.49597870691667e-11], ["bar", "bar", null, "pressure", false, false, 100000], ["barn", "b", null, "area", false, false, 1e-28], ["becquerel", "Bq", null, "radioactivity", true, false, 1], ["bit", "bit", ["b"], "information", false, true, 1], ["btu", "BTU", ["btu"], "energy", false, true, 1055.05585262], ["byte", "byte", null, "information", false, true, 8], ["candela", "cd", null, "luminous_intensity", true, false, 1], ["candela per square metre", "cd/m?", null, "luminance", true, false, 1], ["coulomb", "C", null, "electric_charge", true, false, 1], ["cubic ångström", "ang3", ["ang^3"], "volume", false, true, 1e-30], ["cubic foot", "ft3", ["ft^3"], "volume", false, true, 0.028316846592], ["cubic inch", "in3", ["in^3"], "volume", false, true, 0.000016387064], ["cubic light-year", "ly3", ["ly^3"], "volume", false, true, 8.46786664623715e-47], ["cubic metre", "m?", null, "volume", true, true, 1], ["cubic mile", "mi3", ["mi^3"], "volume", false, true, 4168181825.44058], ["cubic nautical mile", "Nmi3", ["Nmi^3"], "volume", false, true, 6352182208], ["cubic Pica", "Pica3", ["Picapt3", "Pica^3", "Picapt^3"], "volume", false, true, 7.58660370370369e-8], ["cubic yard", "yd3", ["yd^3"], "volume", false, true, 0.764554857984], ["cup", "cup", null, "volume", false, true, 0.0002365882365], ["dalton", "Da", ["u"], "mass", false, false, 1.66053886282828e-27], ["day", "d", ["day"], "time", false, true, 86400], ["degree", "°", null, "angle", false, false, 0.0174532925199433], ["degrees Rankine", "Rank", null, "temperature", false, true, 0.555555555555556], ["dyne", "dyn", ["dy"], "force", false, true, 0.00001], ["electronvolt", "eV", ["ev"], "energy", false, true, 1.60217656514141], ["ell", "ell", null, "length", false, true, 1.143], ["erg", "erg", ["e"], "energy", false, true, 1e-7], ["farad", "F", null, "electric_capacitance", true, false, 1], ["fluid ounce", "oz", null, "volume", false, true, 0.0000295735295625], ["foot", "ft", null, "length", false, true, 0.3048], ["foot-pound", "flb", null, "energy", false, true, 1.3558179483314], ["gal", "Gal", null, "acceleration", false, false, 0.01], ["gallon", "gal", null, "volume", false, true, 0.003785411784], ["gauss", "G", ["ga"], "magnetic_flux_density", false, true, 1], ["grain", "grain", null, "mass", false, true, 0.0000647989], ["gram", "g", null, "mass", false, true, 0.001], ["gray", "Gy", null, "absorbed_dose", true, false, 1], ["gross registered ton", "GRT", ["regton"], "volume", false, true, 2.8316846592], ["hectare", "ha", null, "area", false, true, 10000], ["henry", "H", null, "inductance", true, false, 1], ["hertz", "Hz", null, "frequency", true, false, 1], ["horsepower", "HP", ["h"], "power", false, true, 745.69987158227], ["horsepower-hour", "HPh", ["hh", "hph"], "energy", false, true, 2684519.538], ["hour", "h", ["hr"], "time", false, true, 3600], ["imperial gallon (U.K.)", "uk_gal", null, "volume", false, true, 0.00454609], ["imperial hundredweight", "lcwt", ["uk_cwt", "hweight"], "mass", false, true, 50.802345], ["imperial quart (U.K)", "uk_qt", null, "volume", false, true, 0.0011365225], ["imperial ton", "brton", ["uk_ton", "LTON"], "mass", false, true, 1016.046909], ["inch", "in", null, "length", false, true, 0.0254], ["international acre", "uk_acre", null, "area", false, true, 4046.8564224], ["IT calorie", "cal", null, "energy", false, true, 4.1868], ["joule", "J", null, "energy", true, true, 1], ["katal", "kat", null, "catalytic_activity", true, false, 1], ["kelvin", "K", ["kel"], "temperature", true, true, 1], ["kilogram", "kg", null, "mass", true, true, 1], ["knot", "kn", null, "speed", false, true, 0.514444444444444], ["light-year", "ly", null, "length", false, true, 9460730472580800], ["litre", "L", ["l", "lt"], "volume", false, true, 0.001], ["lumen", "lm", null, "luminous_flux", true, false, 1], ["lux", "lx", null, "illuminance", true, false, 1], ["maxwell", "Mx", null, "magnetic_flux", false, false, 1e-18], ["measurement ton", "MTON", null, "volume", false, true, 1.13267386368], ["meter per hour", "m/h", ["m/hr"], "speed", false, true, 0.00027777777777778], ["meter per second", "m/s", ["m/sec"], "speed", true, true, 1], ["meter per second squared", "m?s??", null, "acceleration", true, false, 1], ["parsec", "pc", ["parsec"], "length", false, true, 30856775814671900], ["meter squared per second", "m?/s", null, "kinematic_viscosity", true, false, 1], ["metre", "m", null, "length", true, true, 1], ["miles per hour", "mph", null, "speed", false, true, 0.44704], ["millimetre of mercury", "mmHg", null, "pressure", false, false, 133.322], ["minute", "?", null, "angle", false, false, 0.000290888208665722], ["minute", "min", ["mn"], "time", false, true, 60], ["modern teaspoon", "tspm", null, "volume", false, true, 0.000005], ["mole", "mol", null, "amount_of_substance", true, false, 1], ["morgen", "Morgen", null, "area", false, true, 2500], ["n.u. of action", "?", null, "action", false, false, 1.05457168181818e-34], ["n.u. of mass", "m?", null, "mass", false, false, 9.10938261616162e-31], ["n.u. of speed", "c?", null, "speed", false, false, 299792458], ["n.u. of time", "?/(me?c??)", null, "time", false, false, 1.28808866778687e-21], ["nautical mile", "M", ["Nmi"], "length", false, true, 1852], ["newton", "N", null, "force", true, true, 1], ["œrsted", "Oe ", null, "magnetic_field_intensity", false, false, 79.5774715459477], ["ohm", "Ω", null, "electric_resistance", true, false, 1], ["ounce mass", "ozm", null, "mass", false, true, 0.028349523125], ["pascal", "Pa", null, "pressure", true, false, 1], ["pascal second", "Pa?s", null, "dynamic_viscosity", true, false, 1], ["pferdestärke", "PS", null, "power", false, true, 735.49875], ["phot", "ph", null, "illuminance", false, false, 0.0001], ["pica (1/6 inch)", "pica", null, "length", false, true, 0.00035277777777778], ["pica (1/72 inch)", "Pica", ["Picapt"], "length", false, true, 0.00423333333333333], ["poise", "P", null, "dynamic_viscosity", false, false, 0.1], ["pond", "pond", null, "force", false, true, 0.00980665], ["pound force", "lbf", null, "force", false, true, 4.4482216152605], ["pound mass", "lbm", null, "mass", false, true, 0.45359237], ["quart", "qt", null, "volume", false, true, 0.000946352946], ["radian", "rad", null, "angle", true, false, 1], ["second", "?", null, "angle", false, false, 0.00000484813681109536], ["second", "s", ["sec"], "time", true, true, 1], ["short hundredweight", "cwt", ["shweight"], "mass", false, true, 45.359237], ["siemens", "S", null, "electrical_conductance", true, false, 1], ["sievert", "Sv", null, "equivalent_dose", true, false, 1], ["slug", "sg", null, "mass", false, true, 14.59390294], ["square ångström", "ang2", ["ang^2"], "area", false, true, 1e-20], ["square foot", "ft2", ["ft^2"], "area", false, true, 0.09290304], ["square inch", "in2", ["in^2"], "area", false, true, 0.00064516], ["square light-year", "ly2", ["ly^2"], "area", false, true, 8.95054210748189e+31], ["square meter", "m?", null, "area", true, true, 1], ["square mile", "mi2", ["mi^2"], "area", false, true, 2589988.110336], ["square nautical mile", "Nmi2", ["Nmi^2"], "area", false, true, 3429904], ["square Pica", "Pica2", ["Picapt2", "Pica^2", "Picapt^2"], "area", false, true, 0.00001792111111111], ["square yard", "yd2", ["yd^2"], "area", false, true, 0.83612736], ["statute mile", "mi", null, "length", false, true, 1609.344], ["steradian", "sr", null, "solid_angle", true, false, 1], ["stilb", "sb", null, "luminance", false, false, 0.0001], ["stokes", "St", null, "kinematic_viscosity", false, false, 0.0001], ["stone", "stone", null, "mass", false, true, 6.35029318], ["tablespoon", "tbs", null, "volume", false, true, 0.0000147868], ["teaspoon", "tsp", null, "volume", false, true, 0.00000492892], ["tesla", "T", null, "magnetic_flux_density", true, true, 1], ["thermodynamic calorie", "c", null, "energy", false, true, 4.184], ["ton", "ton", null, "mass", false, true, 907.18474], ["tonne", "t", null, "mass", false, false, 1000], ["U.K. pint", "uk_pt", null, "volume", false, true, 0.00056826125], ["U.S. bushel", "bushel", null, "volume", false, true, 0.03523907], ["U.S. oil barrel", "barrel", null, "volume", false, true, 0.158987295], ["U.S. pint", "pt", ["us_pt"], "volume", false, true, 0.000473176473], ["U.S. survey mile", "survey_mi", null, "length", false, true, 1609.347219], ["U.S. survey/statute acre", "us_acre", null, "area", false, true, 4046.87261], ["volt", "V", null, "voltage", true, false, 1], ["watt", "W", null, "power", true, true, 1], ["watt-hour", "Wh", ["wh"], "energy", false, true, 3600], ["weber", "Wb", null, "magnetic_flux", true, false, 1], ["yard", "yd", null, "length", false, true, 0.9144], ["year", "yr", null, "time", false, true, 31557600] ]; // Binary prefixes // [Name, Prefix power of 2 value, Previx value, Abbreviation, Derived from] var binary_prefixes = { Yi: ["yobi", 80, 1208925819614629174706176, "Yi", "yotta"], Zi: ["zebi", 70, 1180591620717411303424, "Zi", "zetta"], Ei: ["exbi", 60, 1152921504606846976, "Ei", "exa"], Pi: ["pebi", 50, 1125899906842624, "Pi", "peta"], Ti: ["tebi", 40, 1099511627776, "Ti", "tera"], Gi: ["gibi", 30, 1073741824, "Gi", "giga"], Mi: ["mebi", 20, 1048576, "Mi", "mega"], ki: ["kibi", 10, 1024, "ki", "kilo"] }; // Unit prefixes // [Name, Multiplier, Abbreviation] var unit_prefixes = { Y: ["yotta", 1e+24, "Y"], Z: ["zetta", 1e+21, "Z"], E: ["exa", 1e+18, "E"], P: ["peta", 1e+15, "P"], T: ["tera", 1e+12, "T"], G: ["giga", 1e+09, "G"], M: ["mega", 1e+06, "M"], k: ["kilo", 1e+03, "k"], h: ["hecto", 1e+02, "h"], e: ["dekao", 1e+01, "e"], d: ["deci", 1e-01, "d"], c: ["centi", 1e-02, "c"], m: ["milli", 1e-03, "m"], u: ["micro", 1e-06, "u"], n: ["nano", 1e-09, "n"], p: ["pico", 1e-12, "p"], f: ["femto", 1e-15, "f"], a: ["atto", 1e-18, "a"], z: ["zepto", 1e-21, "z"], y: ["yocto", 1e-24, "y"] }; // Initialize units and multipliers var from = null; var to = null; var base_from_unit = from_unit; var base_to_unit = to_unit; var from_multiplier = 1; var to_multiplier = 1; var alt; // Lookup from and to units for (var i = 0; i < units.length; i++) { alt = (units[i][2] === null) ? [] : units[i][2]; if (units[i][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) { from = units[i]; } if (units[i][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) { to = units[i]; } } // Lookup from prefix if (from === null) { var from_binary_prefix = binary_prefixes[from_unit.substring(0, 2)]; var from_unit_prefix = unit_prefixes[from_unit.substring(0, 1)]; // Handle dekao unit prefix (only unit prefix with two characters) if (from_unit.substring(0, 2) === 'da') { from_unit_prefix = ["dekao", 1e+01, "da"]; } // Handle binary prefixes first (so that 'Yi' is processed before 'Y') if (from_binary_prefix) { from_multiplier = from_binary_prefix[2]; base_from_unit = from_unit.substring(2); } else if (from_unit_prefix) { from_multiplier = from_unit_prefix[1]; base_from_unit = from_unit.substring(from_unit_prefix[2].length); } // Lookup from unit for (var j = 0; j < units.length; j++) { alt = (units[j][2] === null) ? [] : units[j][2]; if (units[j][1] === base_from_unit || alt.indexOf(base_from_unit) >= 0) { from = units[j]; } } } // Lookup to prefix if (to === null) { var to_binary_prefix = binary_prefixes[to_unit.substring(0, 2)]; var to_unit_prefix = unit_prefixes[to_unit.substring(0, 1)]; // Handle dekao unit prefix (only unit prefix with two characters) if (to_unit.substring(0, 2) === 'da') { to_unit_prefix = ["dekao", 1e+01, "da"]; } // Handle binary prefixes first (so that 'Yi' is processed before 'Y') if (to_binary_prefix) { to_multiplier = to_binary_prefix[2]; base_to_unit = to_unit.substring(2); } else if (to_unit_prefix) { to_multiplier = to_unit_prefix[1]; base_to_unit = to_unit.substring(to_unit_prefix[2].length); } // Lookup to unit for (var k = 0; k < units.length; k++) { alt = (units[k][2] === null) ? [] : units[k][2]; if (units[k][1] === base_to_unit || alt.indexOf(base_to_unit) >= 0) { to = units[k]; } } } // Return error if a unit does not exist if (from === null || to === null) { return error.na; } // Return error if units represent different quantities if (from[3] !== to[3]) { return error.na; } // Return converted number return number * from[6] * from_multiplier / (to[6] * to_multiplier); }; exports.DEC2BIN = function(number, places) { number = utils.parseNumber(number); if (number instanceof Error) { return number; } // Return error if number is not decimal, is lower than -512, or is greater than 511 if (!/^-?[0-9]{1,3}$/.test(number) || number < -512 || number > 511) { return error.num; } // Ignore places and return a 10-character binary number if number is negative if (number < 0) { return '1' + text.REPT('0', 9 - (512 + number).toString(2).length) + (512 + number).toString(2); } // Convert decimal number to binary var result = parseInt(number, 10).toString(2); // Return binary number using the minimum number of characters necessary if places is undefined if (typeof places === 'undefined') { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.DEC2HEX = function(number, places) { number = utils.parseNumber(number); if (number instanceof Error) { return number; } // Return error if number is not decimal, is lower than -549755813888, or is greater than 549755813887 if (!/^-?[0-9]{1,12}$/.test(number) || number < -549755813888 || number > 549755813887) { return error.num; } // Ignore places and return a 10-character hexadecimal number if number is negative if (number < 0) { return (1099511627776 + number).toString(16); } // Convert decimal number to hexadecimal var result = parseInt(number, 10).toString(16); // Return hexadecimal number using the minimum number of characters necessary if places is undefined if (typeof places === 'undefined') { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.DEC2OCT = function(number, places) { number = utils.parseNumber(number); if (number instanceof Error) { return number; } // Return error if number is not decimal, is lower than -549755813888, or is greater than 549755813887 if (!/^-?[0-9]{1,9}$/.test(number) || number < -536870912 || number > 536870911) { return error.num; } // Ignore places and return a 10-character octal number if number is negative if (number < 0) { return (1073741824 + number).toString(8); } // Convert decimal number to octal var result = parseInt(number, 10).toString(8); // Return octal number using the minimum number of characters necessary if places is undefined if (typeof places === 'undefined') { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.DELTA = function(number1, number2) { // Set number2 to zero if undefined number2 = (number2 === undefined) ? 0 : number2; number1 = utils.parseNumber(number1); number2 = utils.parseNumber(number2); if (utils.anyIsError(number1, number2)) { return error.value; } // Return delta return (number1 === number2) ? 1 : 0; }; // TODO: why is upper_bound not used ? The excel documentation has no examples with upper_bound exports.ERF = function(lower_bound, upper_bound) { // Set number2 to zero if undefined upper_bound = (upper_bound === undefined) ? 0 : upper_bound; lower_bound = utils.parseNumber(lower_bound); upper_bound = utils.parseNumber(upper_bound); if (utils.anyIsError(lower_bound, upper_bound)) { return error.value; } return jStat.erf(lower_bound); }; // TODO exports.ERF.PRECISE = function() { throw new Error('ERF.PRECISE is not implemented'); }; exports.ERFC = function(x) { // Return error if x is not a number if (isNaN(x)) { return error.value; } return jStat.erfc(x); }; // TODO exports.ERFC.PRECISE = function() { throw new Error('ERFC.PRECISE is not implemented'); }; exports.GESTEP = function(number, step) { step = step || 0; number = utils.parseNumber(number); if (utils.anyIsError(step, number)) { return number; } // Return delta return (number >= step) ? 1 : 0; }; exports.HEX2BIN = function(number, places) { // Return error if number is not hexadecimal or contains more than ten characters (10 digits) if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) { return error.num; } // Check if number is negative var negative = (number.length === 10 && number.substring(0, 1).toLowerCase() === 'f') ? true : false; // Convert hexadecimal number to decimal var decimal = (negative) ? parseInt(number, 16) - 1099511627776 : parseInt(number, 16); // Return error if number is lower than -512 or greater than 511 if (decimal < -512 || decimal > 511) { return error.num; } // Ignore places and return a 10-character binary number if number is negative if (negative) { return '1' + text.REPT('0', 9 - (512 + decimal).toString(2).length) + (512 + decimal).toString(2); } // Convert decimal number to binary var result = decimal.toString(2); // Return binary number using the minimum number of characters necessary if places is undefined if (places === undefined) { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.HEX2DEC = function(number) { // Return error if number is not hexadecimal or contains more than ten characters (10 digits) if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) { return error.num; } // Convert hexadecimal number to decimal var decimal = parseInt(number, 16); // Return decimal number return (decimal >= 549755813888) ? decimal - 1099511627776 : decimal; }; exports.HEX2OCT = function(number, places) { // Return error if number is not hexadecimal or contains more than ten characters (10 digits) if (!/^[0-9A-Fa-f]{1,10}$/.test(number)) { return error.num; } // Convert hexadecimal number to decimal var decimal = parseInt(number, 16); // Return error if number is positive and greater than 0x1fffffff (536870911) if (decimal > 536870911 && decimal < 1098974756864) { return error.num; } // Ignore places and return a 10-character octal number if number is negative if (decimal >= 1098974756864) { return (decimal - 1098437885952).toString(8); } // Convert decimal number to octal var result = decimal.toString(8); // Return octal number using the minimum number of characters necessary if places is undefined if (places === undefined) { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.IMABS = function(inumber) { // Lookup real and imaginary coefficients using exports.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); // Return error if either coefficient is not a number if (utils.anyIsError(x, y)) { return error.value; } // Return absolute value of complex number return Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)); }; exports.IMAGINARY = function(inumber) { if (inumber === undefined || inumber === true || inumber === false) { return error.value; } // Return 0 if inumber is equal to 0 if (inumber === 0 || inumber === '0') { return 0; } // Handle special cases if (['i', 'j'].indexOf(inumber) >= 0) { return 1; } // Normalize imaginary coefficient inumber = inumber.replace('+i', '+1i').replace('-i', '-1i').replace('+j', '+1j').replace('-j', '-1j'); // Lookup sign var plus = inumber.indexOf('+'); var minus = inumber.indexOf('-'); if (plus === 0) { plus = inumber.indexOf('+', 1); } if (minus === 0) { minus = inumber.indexOf('-', 1); } // Lookup imaginary unit var last = inumber.substring(inumber.length - 1, inumber.length); var unit = (last === 'i' || last === 'j'); if (plus >= 0 || minus >= 0) { // Return error if imaginary unit is neither i nor j if (!unit) { return error.num; } // Return imaginary coefficient of complex number if (plus >= 0) { return (isNaN(inumber.substring(0, plus)) || isNaN(inumber.substring(plus + 1, inumber.length - 1))) ? error.num : Number(inumber.substring(plus + 1, inumber.length - 1)); } else { return (isNaN(inumber.substring(0, minus)) || isNaN(inumber.substring(minus + 1, inumber.length - 1))) ? error.num : -Number(inumber.substring(minus + 1, inumber.length - 1)); } } else { if (unit) { return (isNaN(inumber.substring(0, inumber.length - 1))) ? error.num : inumber.substring(0, inumber.length - 1); } else { return (isNaN(inumber)) ? error.num : 0; } } }; exports.IMARGUMENT = function(inumber) { // Lookup real and imaginary coefficients using exports.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); // Return error if either coefficient is not a number if (utils.anyIsError(x, y)) { return error.value; } // Return error if inumber is equal to zero if (x === 0 && y === 0) { return error.div0; } // Return PI/2 if x is equal to zero and y is positive if (x === 0 && y > 0) { return Math.PI / 2; } // Return -PI/2 if x is equal to zero and y is negative if (x === 0 && y < 0) { return -Math.PI / 2; } // Return zero if x is negative and y is equal to zero if (y === 0 && x > 0) { return 0; } // Return zero if x is negative and y is equal to zero if (y === 0 && x < 0) { return -Math.PI; } // Return argument of complex number if (x > 0) { return Math.atan(y / x); } else if (x < 0 && y >= 0) { return Math.atan(y / x) + Math.PI; } else { return Math.atan(y / x) - Math.PI; } }; exports.IMCONJUGATE = function(inumber) { // Lookup real and imaginary coefficients using exports.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return conjugate of complex number return (y !== 0) ? exports.COMPLEX(x, -y, unit) : inumber; }; exports.IMCOS = function(inumber) { // Lookup real and imaginary coefficients using exports.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return cosine of complex number return exports.COMPLEX(Math.cos(x) * (Math.exp(y) + Math.exp(-y)) / 2, -Math.sin(x) * (Math.exp(y) - Math.exp(-y)) / 2, unit); }; exports.IMCOSH = function(inumber) { // Lookup real and imaginary coefficients using exports.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return hyperbolic cosine of complex number return exports.COMPLEX(Math.cos(y) * (Math.exp(x) + Math.exp(-x)) / 2, Math.sin(y) * (Math.exp(x) - Math.exp(-x)) / 2, unit); }; exports.IMCOT = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Return cotangent of complex number return exports.IMDIV(exports.IMCOS(inumber), exports.IMSIN(inumber)); }; exports.IMDIV = function(inumber1, inumber2) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var a = exports.IMREAL(inumber1); var b = exports.IMAGINARY(inumber1); var c = exports.IMREAL(inumber2); var d = exports.IMAGINARY(inumber2); if (utils.anyIsError(a, b, c, d)) { return error.value; } // Lookup imaginary unit var unit1 = inumber1.substring(inumber1.length - 1); var unit2 = inumber2.substring(inumber2.length - 1); var unit = 'i'; if (unit1 === 'j') { unit = 'j'; } else if (unit2 === 'j') { unit = 'j'; } // Return error if inumber2 is null if (c === 0 && d === 0) { return error.num; } // Return exponential of complex number var den = c * c + d * d; return exports.COMPLEX((a * c + b * d) / den, (b * c - a * d) / den, unit); }; exports.IMEXP = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return exponential of complex number var e = Math.exp(x); return exports.COMPLEX(e * Math.cos(y), e * Math.sin(y), unit); }; exports.IMLN = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return exponential of complex number return exports.COMPLEX(Math.log(Math.sqrt(x * x + y * y)), Math.atan(y / x), unit); }; exports.IMLOG10 = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return exponential of complex number return exports.COMPLEX(Math.log(Math.sqrt(x * x + y * y)) / Math.log(10), Math.atan(y / x) / Math.log(10), unit); }; exports.IMLOG2 = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return exponential of complex number return exports.COMPLEX(Math.log(Math.sqrt(x * x + y * y)) / Math.log(2), Math.atan(y / x) / Math.log(2), unit); }; exports.IMPOWER = function(inumber, number) { number = utils.parseNumber(number); var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(number, x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Calculate power of modulus var p = Math.pow(exports.IMABS(inumber), number); // Calculate argument var t = exports.IMARGUMENT(inumber); // Return exponential of complex number return exports.COMPLEX(p * Math.cos(number * t), p * Math.sin(number * t), unit); }; exports.IMPRODUCT = function() { // Initialize result var result = arguments[0]; if (!arguments.length) { return error.value; } // Loop on all numbers for (var i = 1; i < arguments.length; i++) { // Lookup coefficients of two complex numbers var a = exports.IMREAL(result); var b = exports.IMAGINARY(result); var c = exports.IMREAL(arguments[i]); var d = exports.IMAGINARY(arguments[i]); if (utils.anyIsError(a, b, c, d)) { return error.value; } // Complute product of two complex numbers result = exports.COMPLEX(a * c - b * d, a * d + b * c); } // Return product of complex numbers return result; }; exports.IMREAL = function(inumber) { if (inumber === undefined || inumber === true || inumber === false) { return error.value; } // Return 0 if inumber is equal to 0 if (inumber === 0 || inumber === '0') { return 0; } // Handle special cases if (['i', '+i', '1i', '+1i', '-i', '-1i', 'j', '+j', '1j', '+1j', '-j', '-1j'].indexOf(inumber) >= 0) { return 0; } // Lookup sign var plus = inumber.indexOf('+'); var minus = inumber.indexOf('-'); if (plus === 0) { plus = inumber.indexOf('+', 1); } if (minus === 0) { minus = inumber.indexOf('-', 1); } // Lookup imaginary unit var last = inumber.substring(inumber.length - 1, inumber.length); var unit = (last === 'i' || last === 'j'); if (plus >= 0 || minus >= 0) { // Return error if imaginary unit is neither i nor j if (!unit) { return error.num; } // Return real coefficient of complex number if (plus >= 0) { return (isNaN(inumber.substring(0, plus)) || isNaN(inumber.substring(plus + 1, inumber.length - 1))) ? error.num : Number(inumber.substring(0, plus)); } else { return (isNaN(inumber.substring(0, minus)) || isNaN(inumber.substring(minus + 1, inumber.length - 1))) ? error.num : Number(inumber.substring(0, minus)); } } else { if (unit) { return (isNaN(inumber.substring(0, inumber.length - 1))) ? error.num : 0; } else { return (isNaN(inumber)) ? error.num : inumber; } } }; exports.IMSEC = function(inumber) { // Return error if inumber is a logical value if (inumber === true || inumber === false) { return error.value; } // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Return secant of complex number return exports.IMDIV('1', exports.IMCOS(inumber)); }; exports.IMSECH = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Return hyperbolic secant of complex number return exports.IMDIV('1', exports.IMCOSH(inumber)); }; exports.IMSIN = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return sine of complex number return exports.COMPLEX(Math.sin(x) * (Math.exp(y) + Math.exp(-y)) / 2, Math.cos(x) * (Math.exp(y) - Math.exp(-y)) / 2, unit); }; exports.IMSINH = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Return hyperbolic sine of complex number return exports.COMPLEX(Math.cos(y) * (Math.exp(x) - Math.exp(-x)) / 2, Math.sin(y) * (Math.exp(x) + Math.exp(-x)) / 2, unit); }; exports.IMSQRT = function(inumber) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Lookup imaginary unit var unit = inumber.substring(inumber.length - 1); unit = (unit === 'i' || unit === 'j') ? unit : 'i'; // Calculate power of modulus var s = Math.sqrt(exports.IMABS(inumber)); // Calculate argument var t = exports.IMARGUMENT(inumber); // Return exponential of complex number return exports.COMPLEX(s * Math.cos(t / 2), s * Math.sin(t / 2), unit); }; exports.IMCSC = function (inumber) { // Return error if inumber is a logical value if (inumber === true || inumber === false) { return error.value; } // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); // Return error if either coefficient is not a number if (utils.anyIsError(x, y)) { return error.num; } // Return cosecant of complex number return exports.IMDIV('1', exports.IMSIN(inumber)); }; exports.IMCSCH = function (inumber) { // Return error if inumber is a logical value if (inumber === true || inumber === false) { return error.value; } // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); // Return error if either coefficient is not a number if (utils.anyIsError(x, y)) { return error.num; } // Return hyperbolic cosecant of complex number return exports.IMDIV('1', exports.IMSINH(inumber)); }; exports.IMSUB = function(inumber1, inumber2) { // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var a = this.IMREAL(inumber1); var b = this.IMAGINARY(inumber1); var c = this.IMREAL(inumber2); var d = this.IMAGINARY(inumber2); if (utils.anyIsError(a, b, c, d)) { return error.value; } // Lookup imaginary unit var unit1 = inumber1.substring(inumber1.length - 1); var unit2 = inumber2.substring(inumber2.length - 1); var unit = 'i'; if (unit1 === 'j') { unit = 'j'; } else if (unit2 === 'j') { unit = 'j'; } // Return _ of two complex numbers return this.COMPLEX(a - c, b - d, unit); }; exports.IMSUM = function() { if (!arguments.length) { return error.value; } var args = utils.flatten(arguments); // Initialize result var result = args[0]; // Loop on all numbers for (var i = 1; i < args.length; i++) { // Lookup coefficients of two complex numbers var a = this.IMREAL(result); var b = this.IMAGINARY(result); var c = this.IMREAL(args[i]); var d = this.IMAGINARY(args[i]); if (utils.anyIsError(a, b, c, d)) { return error.value; } // Complute product of two complex numbers result = this.COMPLEX(a + c, b + d); } // Return sum of complex numbers return result; }; exports.IMTAN = function(inumber) { // Return error if inumber is a logical value if (inumber === true || inumber === false) { return error.value; } // Lookup real and imaginary coefficients using Formula.js [http://formulajs.org] var x = exports.IMREAL(inumber); var y = exports.IMAGINARY(inumber); if (utils.anyIsError(x, y)) { return error.value; } // Return tangent of complex number return this.IMDIV(this.IMSIN(inumber), this.IMCOS(inumber)); }; exports.OCT2BIN = function(number, places) { // Return error if number is not hexadecimal or contains more than ten characters (10 digits) if (!/^[0-7]{1,10}$/.test(number)) { return error.num; } // Check if number is negative var negative = (number.length === 10 && number.substring(0, 1) === '7') ? true : false; // Convert octal number to decimal var decimal = (negative) ? parseInt(number, 8) - 1073741824 : parseInt(number, 8); // Return error if number is lower than -512 or greater than 511 if (decimal < -512 || decimal > 511) { return error.num; } // Ignore places and return a 10-character binary number if number is negative if (negative) { return '1' + text.REPT('0', 9 - (512 + decimal).toString(2).length) + (512 + decimal).toString(2); } // Convert decimal number to binary var result = decimal.toString(2); // Return binary number using the minimum number of characters necessary if places is undefined if (typeof places === 'undefined') { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } }; exports.OCT2DEC = function(number) { // Return error if number is not octal or contains more than ten characters (10 digits) if (!/^[0-7]{1,10}$/.test(number)) { return error.num; } // Convert octal number to decimal var decimal = parseInt(number, 8); // Return decimal number return (decimal >= 536870912) ? decimal - 1073741824 : decimal; }; exports.OCT2HEX = function(number, places) { // Return error if number is not octal or contains more than ten characters (10 digits) if (!/^[0-7]{1,10}$/.test(number)) { return error.num; } // Convert octal number to decimal var decimal = parseInt(number, 8); // Ignore places and return a 10-character octal number if number is negative if (decimal >= 536870912) { return 'ff' + (decimal + 3221225472).toString(16); } // Convert decimal number to hexadecimal var result = decimal.toString(16); // Return hexadecimal number using the minimum number of characters necessary if places is undefined if (places === undefined) { return result; } else { // Return error if places is nonnumeric if (isNaN(places)) { return error.value; } // Return error if places is negative if (places < 0) { return error.num; } // Truncate places in case it is not an integer places = Math.floor(places); // Pad return value with leading 0s (zeros) if necessary (using Underscore.string) return (places >= result.length) ? text.REPT('0', places - result.length) + result : error.num; } };