The exact-math library is a set of methods for math calculations like: adding, subtracting, multiplying, dividing, rounding, flooring, ceiling and powering.
It also allows to use [String] math formulas, eg. 5.55*(7/.33)-2
It works with big numbers and small decimals and gives a precise result.
It allows to use [String|Number] values and it gives the [String|Number] result.
npm install exact-math --save
const exactMath = require('exact-math');
exactMath.add(5, 5); //10
exactMath.sub('25.5','.5'); //25
exactMath.mul(2, '2', 5, .1); //2
exactMath.div('55', 2); //27,5
exactMath.formula('4*(12/3)-7.77'); //8.23
exactMath.round(123456, 5) //120000
exactMath.ceil(0.123456789, -3) //0.124
exactMath.floor(9.999, 1) //9
exactMath.pow(2, 5); //32
exact-math.js library to the HTML file.The library is located in ./dist/exact-math.js directory.
It is a webpack&babel bundled cross-browser library version.
The library is accessible as exactMath variable in the global (window) scope.
<head>
<script src='exact-math.js'></script>
<script>
var result = exactMath.mul(.5, .3);
</script>
</head>
> git clone https://github.com/devrafalko/exact-math.git
> cd exact-math
> npm install
> npm test
exact-math works compared with the JS regular arithmetic operationsmin: 1 max: 5 step: 0.1 number: 2 select: multiplicationexact-math resolves the floating point problem and returns the precise result| Code | JavaScript result | exact-math result |
|---|---|---|
0.1 + 0.2 |
0.30000000000000004 | 0.3 |
0.4 * 0.2 |
0.08000000000000002 | 0.08 |
0.45 - 0.15 |
0.30000000000000004 | 0.3 |
.82 / 10 |
0.08199999999999999 | 0.082 |
1.4 - 0.6 - 0.4 - 0.4 |
-1.1102230246251565e-16 | 0 |
2⁵³-1 or lower than -2⁵³-1) [read more] the result of calculation is not preciseexact-math does the calculations on big integers and small decimals and gives a precise resultconst config = { returnString: true };
let result = exactMath.sub('92179342550763210809069221175572', '11779955999989769291989599', config);
//'92179330770807210819299929185973'
let result = exactMath.add('3.00000000000000000015', '12.00000000000000020020', config);
//'15.00000000000000020035'
2*(5+.3)/13*(2.2*4), it must be the part of the code or the eval() method must be usedexact-math allows to calculate the [String] arithmetic formulas, using regular expressions to parse the given formula rather than eval() [see below]Math.round method allows to round the value only to the nearest integers. In order to round the value to the chosen decimal place or to the tens, hundreds, thousands, etc., you need some workaroundsexact-math allows to round, floor and ceil the values both to the whole integers (ones, tens, hundreds, thousands, etc.) and decimals (tenths, hundredths, thousandths, ten-thousandths, etc.) [see below]add, sub, mul, div
add,sub,mulanddivmethods take the same arguments
x, yType: [Number|String]
| two or more [Number | String] numerical values must be passed as the arguments |
z argument and the next ones numerical values are optional1.5, 2e+3, -.4'1.5', '2e+3', '-.4'NaN, Infinity and -Infinityformulaformula is an arithmetical formulaexact-math uses regular expressions to parse [String] formula into the regular JavaScript formulaeval()formula can contain:
[0-9] digits1.5, 0.5 or .5 decimal fractions-5, -.4, -5.55 negative values2e-2, .25e+12, -3e-10 exponential notation values* multiplication sign (also x and ⋅ [see config.mulChar])/ division sign (also : and ÷ [see config.divChar])+ plus sign- subtraction sign( and ) parentheses4(2+1) is equal to 4*(2+1)2 * -2 equals to 2 * (-2)2 / -2 equals to 2 / (-2)+2 + 2 equals to 2 + 22 + +2 equals to 2 + 2-2 - -2 equals to -2 + 2-2 - +2 equals to -2 - 2-2 + -2 equals to -2 - 22 + 22 + ( -2 - -2) 2 + (+2 + +4 / -1) -.1 - -52 + 3e-5.25e+5 * -.25e-5-2 - - 25 + . 3.2 e-5, 2e - 5, 3e +10round, ceil, floor
round,ceilandfloormethods take the same arguments
valueType: [Number|String]
| one [Number | String] numerical value must be passed as the argument |
1.5, 2e+3, -.4'1.5', '2e+3', '-.4'NaN, Infinity and -InfinityplacesType: [Number] (optional)
Default: 1
value will be rounded (or rounded up when ceil or rounded down when floor) to the places digitplaces must be a positive or negative [Number] integerplaces value rounds the value to the decimals. The positive places value rounds the value to the integers.0 returns the given value without rounding it.places argument is omitted, the default 1 value is usedplaces |
exactMath.round | exactMath.floor | exactMath.ceil |
|---|---|---|---|
0 |
14993.00159 |
14993.00159 |
14993.00159 |
1 |
14993 |
14993 |
14994 |
2 |
14990 |
14990 |
15000 |
3 |
15000 |
14900 |
15000 |
4 |
15000 |
14000 |
15000 |
5 |
10000 |
10000 |
20000 |
6 |
0 |
0 |
100000 |
-1 |
14993 |
14993 |
14993.1 |
-2 |
14993 |
14993 |
14993.01 |
-3 |
14993.002 |
14993.001 |
14993.002 |
-4 |
14993.0016 |
14993.0015 |
14993.0016 |
-5 |
14993.00159 |
14993.00159 |
14993.00159 |
powvalueType: [Number|String]
| one [Number | String] numerical value must be passed as the argument |
1.5, 2e+3, -.4'1.5', '2e+3', '-.4'NaN, Infinity and -InfinitypowerType: [Number] (optional)
Default: 2
value will be raised to the power exponentpower must be a positive [Number] integervalue raised to the 0 power returns the 1 as a result, according to the approved mathematical conventionpower argument is omitted, the default 2 value is usedconfig parameterconfigType: [Object|Boolean] optional
Default: false
exact-math method may take the config argument. It allows to configure the additional settings.config argument can be passed as [Object] object with config properties or as [Boolean] valueconfig argument is passed as true, it is the shortcut of the config.returnString property set to true [samples]config argument is passed as false or if it is not defined (it is set to false by default then), it is the shortcut of the config.returnString property set to false [samples]config argument is passed as [Object] object, it may take the config properties [described below]config argument is not passed or if some [Object] config properties are not defined or defined with the incorrect type or value, the default values are used instead for these propertiesconfig properties:returnStringType: [Boolean]
Default: false
2⁵³-1 or -2⁵³-1, the [Number] value may be inaccurate; Number('1111222233334444567') ==> 1111222233334444500returnString property is set to true, the accuare [String] value is returned; '1111222233334444567'.exact-math calculations as it takes the [String] numerical value arguments [see above]If you use [Number] unsafe values for the computation, the imprecise result is returned;
eg.exactMath.add(100000000000000000055,5.00000000000000022).
If you use [Number] safe values for the computation it may still return the imprecise unsafe result value;
eg.exactMath.mul(101101000110,10010110010001) => 1.0120321332222232e+24.
In order to avoid the imprecise results always use [String] numerical values for the calculations and set theconfig.returnStringparameter totrue.
The [String] numerical values passed as the arguments and the [String] result returned by theexact-mathare always safe.
decimalCharType: [String|Array:string]
Default: ['.', ',']
. period character, while out-of-coding notations sometimes also allows , comma character. and , will be ignored). The default value will be used, if the illegal value has been passeddecimalChar settings samples: ',', '.', ['.'], [','], ['.', ','], etc.. and , character, eg: '4,5', '3.5 + 2,2', '0,55 / 6.22'.. character (and thereby forbid , character), set decimalChar property to [String] . or [Array] ['.']exact-math module to calculate some result. The , usage would not throw an error thendivCharType: [String|Array:string]
Default: ['/', ':', '÷']
formula method/ character, while out-of-coding notations sometimes also allows : colon or ÷ division sign (unicode: '\u00F7') characterformula division operations (the characters other than /, : and ÷ will be ignored). The default value will be used, if the illegal value has been passeddivChar settings samples: '/', ':', '÷' ['/', ':'], [':', '÷'], ['÷', ':', '/'], ['/'], etc./, : and ÷ for division operations, eg: '22 / 4', 100:2, '4.5 * (5÷.1)/3'/ character (and thereby forbid : and ÷ character), set divChar property to [String] / or [Array] ['/']exact-math.formula method to calculate some result. The : or ÷ usage would not throw an error thenmulCharType: [String|Array:string]
Default: ['*', 'x', '⋅']
formula method* character, while out-of-coding notations sometimes also allows x or ⋅ dot operator (unicode: '\u22C5') characterformula multiplication operations (the characters other than *, x and ⋅ will be ignored). The default value will be used, if the illegal value has been passedmulChar settings samples: '*', 'x', '⋅', ['*', 'x', '⋅'], ['*'], ['x'], ['*', '⋅'] etc.*, x and ⋅ for multiplication operations, eg: '5 * 4', 4x2, '4.5 * (3x.2)*3', '3 ⋅ 3 \ 2'* character (and thereby forbid x and ⋅ character), set mulChar property to [String] * or [Array] ['*']exact-math.formula method to calculate some result. The x or ⋅ usage would not throw an error theneMinusType: [Number]
Default: 7
config.returnString property is set to true or when the callback is passed)7 or more decimal places and it begins with zeros, eg. '0.01', '0.00001', but '0.1e-7' rather than '0.00000001'.eMinus property to the other than default [Number] positive integer to decide when the decimal result should be written with exponential notationInfinity if the decimal value should never be presented with exponential notation, regardless of how long the [String] decimal value iseMinus does not round the value (like Number.prototype.toExponential) - it only shorten the long-zero values when possible, eg. the 0.123123123123123 will never be shorthenedexact-math, whether the [String] value with exponential notation, or without, is passed as the argument for the calculation: exactMath.add('0.00005','5e-5')ePlusType: [Number]
Default: 21
config.returnString property is set to true or when the callback is passed)21 or more digits and it ends with zeros, eg. '10000', '10000000000', but '1e+21' rather than '1000000000000000000000' and 1000000000005e+8 rather than 100000000000500000000ePlus property to the other than default [Number] positive integer to decide when the integer result should be written with exponential notationInfinity if the integer value should never be presented with exponential notation, regardless of how long the [String] integer value isePlus does not round the value (like Number.prototype.toExponential) - it only shorten the long-zero values when possible, eg. the 123123123123 will never be shorthenedexact-math, whether the [String] value with exponential notation, or without, is passed as the argument for the calculation: exactMath.add('1e+21','1000000000000000000000')maxDecimalType: [Number]
Default: 17
formula method)maxDecimal property indicates the maximal number of decimal places of the [String] result value, to avoid stack overflow17, it is rounded to 17 decimal placesmaxDecimal property with a desirable integer valuemaxDecimal [Number] value must be an integer, bigger or equal to 0 and cannot be an InfinitydivideByZeroErrorType: [Boolean|Error|Function]
Default: false
false, when the value is divided by 0 or if the 0 is divided by 0 - the NaN is returned as the resulttrue in order to throw the default error; This error will be thrown only if the callback is not defined. Otherwise it is accessible via the error property in the callback function.callback is not defined. Otherwise it is accessible via the error property in the callback function.callback function (if defined)exact-math as the result of the calculation rather than the default NaNerror: the default errorindex: the [Number] index of 0-value argument (for div method, otherwise it is undefined)list: the [Array] list of all passed valuescallback: the reference to the [Function] callback (if defined, otherwise it is undefined)invalidErrorType: [Boolean|Error|Function]
Default: true
true, if the argument of incorrect type has been passed, or if it hasn’t been passed when required, or if any of the passed numerical value arguments is [String] incorrect value, is NaN, Infinity or -Infinity (that is forbidden) - the default error is thrown; This error will be thrown only if the callback is not defined. Otherwise it is accessible via the error property in the callback function.false and the NaN will be returned as the result without throwing an errorcallback is not defined. Otherwise it is accessible via the error property in the callback function.callback function (if defined)exact-math as the result of the calculation rather than the default NaNerror: the default errorindex: the [Number] index of the incorrect argument, (otherwise, if the error does not concern the argument, it is undefined)list: the [Array] list of all passed valuescallback: the reference to the [Function] callback (if defined, otherwise it is undefined)callback parametercallbackType: [Function] optional
Default: undefined
callback argument is defined, the config.divideByZeroError or config.invalidError error is not thrown automaticallycallback is called with the one [Object] argument passed with the following properties:
errorconfig.divideByZeroError or config.invalidError is set to true, it refers to the default error.config.divideByZeroError or config.invalidError is set to [Error], it refers to this error.null.numbererror is null, it is the [Number] result value of the calculation.NaNstringerror is null, it is the [String] result value of the calculation.config.returnString property.NaN.>2⁵³-1 || <-2⁵³-1.exact-math calculations.config.returnString property is set to trueNaN is returned if the config.invalidError property is set to false and one of the passed arguments is invalidNaN is returned if the config.divideByZeroError property is set to false and the value is divided by 0 or if 0 is divided by 0| the object | value returned in the [Function] config.divideByZeroError or config.invalidError is returned if this function has been called as the sequence of an error occurance |
addition, subtraction, division and multiplication methods usageconst exactMath = require('exact-math');
exactMath.add(7, -7, '223', -223); //0
exactMath.add('234.4564395832045903', '-645.266756645345334545345', true); //'-410.810317062140744245345'
exactMath.sub('3.0000000000000005', '2.0000000000000001', '1.0000000000000003'); //1e-16
exactMath.sub('292855679192089e-24', '79958000101700102e-24', true); //'-7.9665144422508013e-8'
exactMath.mul('0.000000001020050888', '0.000000100777030252', true); //'1.02797699198555463776e-16'
exactMath.mul('2345205680246529456', '34957892456802348602346', true); //'81983447959140172789843887025738719703776'
exactMath.div(10, 2, 2, 2, 2); //0.625
exactMath.div(432.5, .11, '2.000000000044', true); //'1965.90909086584090909'
formula method usageconst exactMath = require('exact-math');
exactMath.formula('2 + 2'); //4
exactMath.formula('3*(5-2)'); //9
exactMath.formula(' 2.5 * 2.5 / .1'); //62.5
exactMath.formula('3.5+5*(-4-(3/(3+1)-12*3-.2*22)-16/4*12-5/(2)+3.5+2.5*(1.5-2*7))-16'); //-225.5
exactMath.formula('.25e+2*10'); //250
round, ceil and floor methods usageconst exactMath = require('exact-math');
exactMath.round(880225, 4); //880000
exactMath.ceil(99999995, 4); //100000000
exactMath.floor(99999995, 3); //99999900
exactMath.ceil(0.123, 3); //100
exactMath.ceil(0.000028, -1); //0.1
exactMath.round(0.000028, -5); //0.00003
exactMath.floor(0.000028, -5); //0.00002
exactMath.floor('99999.0000009910009', -5); //99999
exactMath.ceil('99999.0000009910009', -5); //99999.00001
pow method usageconst exactMath = require('exact-math');
exactMath.pow(2, 0); //1
exactMath.pow(155.55, 0); //1
exactMath.pow(2, 1); //2
exactMath.pow(2, 2); //4
exactMath.pow(2, 100, { returnString: true }); //'1267650600228229401496703205376'
exactMath.pow(-2, 6); //64
exactMath.pow(5.55, 5); //948.79400625
exactMath.pow(.1, 150); //1e-150
returnString property set as [Boolean] argumentconst exactMath = require('exact-math');
exactMath.add(22, 55); //77 [Number]
exactMath.add(22, 55, false); //77 [Number]
exactMath.add(22, 55, true); //'77' [String]
exactMath.mul('0.20', '0.3000000'); //0.06 [Number]
exactMath.div('9947619', 25, false); //397904.76 [Number]
exactMath.round('99999.0000009910009', -7, true); //'99999.000001' [String]
exactMath.sub(0.000008, 0.000003); //0.000005 [Number]
exactMath.floor('9081726354.4536271809', -2, false); //9081726354.45 [Number]
exactMath.pow(10, 19, true); //'10000000000000000000' [String]
returnString property usageconst exactMath = require('exact-math');
exactMath.add(2, 2, { returnString: false }); //4
exactMath.sub('100', '5', { returnString: false }); //95
exactMath.round(2.22, -1, { returnString: true }); //'2.2'
exactMath.pow(3, 3, { returnString: true }) //'27'
decimalChar property usageconst exactMath = require('exact-math');
exactMath.add('5.55', '3,33'); //8.88
exactMath.sub('5.55', '3,33', { decimalChar: ['.', ','] }); //2.22
exactMath.mul('5.55', '3,33', { decimalChar: '.' }); //[Error]: Incorrect argument [1]. The [String] argument is not a valid numerical value.
exactMath.formula('5.55 + 3,33', { decimalChar: ',' }) //[Error]: The [String] formula contains illegal character .
divChar property usageconst exactMath = require('exact-math');
exactMath.formula('(6÷2)*(4/2)*(9:.5)'); //108
exactMath.formula('(6÷2)*(4/2)*(9:.5)', { divChar: ['÷', ':', '/'] }); //108
exactMath.formula('(6÷2)*(4/2)*(9:.5)', { divChar: [':', '÷'] }); //[Error]: The [String] formula contains illegal character /
exactMath.formula('10/2', { divChar: ['/'] }); //5
exactMath.formula('10÷2', { divChar: ['÷'] }); //5
mulChar property usageconst exactMath = require('exact-math');
exactMath.formula('5*5 + 5x5 + 5⋅5'); //75
exactMath.formula('5*5 + 5x5 + 5⋅5', { mulChar: ['*', 'x', '⋅'] }); //75
exactMath.formula('5*5 + 5x5 + 5⋅5', { mulChar: ['x'] }); //[Error]: The [String] formula contains illegal character *
exactMath.formula('5*5', { mulChar: '*' }); //25
exactMath.formula('5*5 + 5⋅5', { mulChar: ['*', '⋅'] }); //50
ePlus and eMinus properties usageconst exactMath = require('exact-math');
exactMath.add('1005000000000','4400000000000000000000000', { returnString: true }); //'4400000000001005e+9'
exactMath.add('0.0000000000000001','0.000000000000000000001', { returnString: true }); //'1.00001e-16'
exactMath.sub('0.0000012',0.000023, { returnString: true }); //'-2.18e-5'
exactMath.mul(0.000005,0.000005, { returnString: true }); //'2.5e-11'
exactMath.formula('1e+5*1e+5*1e+5*1e+5', { returnString: true }); //'1e+20'
exactMath.formula('1/10000000', { returnString: true }); //'1e-7'
exactMath.add('5000', 5000, { returnString: true, ePlus: 0 }); //'1e+4'
exactMath.mul(200,400,600,800,1000,1200,1400,1600, { returnString: true, ePlus: 25 }); //'103219200000000000000000'
exactMath.div(1, 10e+10, { returnString: true, eMinus: 0 }); //'1e-11'
exactMath.formula('6(.2*.15)/1000+2/2000*.00000022', { returnString: true, eMinus: 12 }); //'0.00018000022'
exactMath.pow(0.3, 20, { returnString: true, eMinus: 0 }); //'3.486784401e-11'
exactMath.pow(0.3, 20, { returnString: true, eMinus: 21 }); //'0.00000000003486784401'
exactMath.add('200000','500000000000','10000000000000000','62000000000000000000000000000000', { returnString: true, ePlus: Infinity }); //'62000000000000010000500000200000'
exactMath.pow(0.037, 17, { returnString: true, eMinus: Infinity }); //'0.000000000000000000000000456487940826035155404146917'
maxDecimal property usageconst exactMath = require('exact-math');
exactMath.div(16.22, 7.77, { returnString: true }); //'2.08751608751608752'
exactMath.div(16.22, 7.77, { returnString: true, maxDecimal: 5 }); //'2.08752'
exactMath.div(16.22, 7.77, { returnString: true, maxDecimal: 25 }); //'2.0875160875160875160875161'
exactMath.formula('2/3.33+2/3.33', { returnString: true}); //'1.2012012012012012'
exactMath.formula('2/3.33+2/3.33', { returnString: true, maxDecimal: 1 }); //'1.2'
exactMath.formula('2/3.33+2/3.33', { returnString: true, naxDecimal: 30}); //'1.201201201201201201201201201202'
divideByZeroError property usageconst exactMath = require('exact-math');
const config = { divideByZeroError: false };
exactMath.div(0, 0); //NaN
exactMath.formula('2/0'); //NaN
exactMath.div(55, 0, 2.5, config); //NaN
exactMath.formula('2*(9/(2-2))', config); //NaN
const exactMath = require('exact-math');
const config = { divideByZeroError: true };
exactMath.div(55, 0, 2.5, config); //[Error]: Incorrect argument [1]. The division by zero is not allowed.
exactMath.formula('2*(9/(2-2))', config); //[Error]: Invalid '(9/(2-2))' expression. The division by zero is not allowed.
exactMath.div(55, 0, 2.5, config, (o)=>{
console.log(o.number); //NaN
console.error(o.error); //[Error]: Incorrect argument [1]. The division by zero is not allowed.
});
const exactMath = require('exact-math');
const customError = new Error('Division by zero.');
const config = { divideByZeroError: customError };
exactMath.div(55, 0, 2.5, config); //[Error]: Division by zero.
exactMath.formula('2*(9/(2-2))', config); //[Error]: Division by zero.
exactMath.div(55, 0, 2.5, config, (o)=>{
console.log(o.number); //NaN
console.error(o.error); //[Error]: Division by zero.
});
const exactMath = require('exact-math');
const config = {
divideByZeroError: ({ list }) => {
if(list[0] != 0) return Infinity;
else return NaN;
}
};
console.log(exactMath.div(0, 0, config)); //NaN
console.log(exactMath.div(0, 1, config)); //0
console.log(exactMath.div(1, 0, config)); //Infinity
invalidError property usageconst exactMath = require('exact-math');
exactMath.add(Infinity, 5); //[TypeError]: Incorrect argument [0]. The argument cannot be an Infinity or -Infinity value.
exactMath.add(Infinity, 5, { invalidError: true}); //[TypeError]: Incorrect argument [0]. The argument cannot be an Infinity or -Infinity value.
exactMath.div(10, NaN); //[TypeError]: Incorrect argument [1]. The argument cannot be a NaN value.
exactMath.div(10, NaN, { invalidError: true}); //[TypeError]: Incorrect argument [1]. The argument cannot be a NaN value.
exactMath.sub(); //[Error]: Set at least two [Number|String] values.
exactMath.pow(2, 2.5); //[Error]: Incorrect argument [1]. The [Number] power exponent positive integer is expected.
const exactMath = require('exact-math');
const config = { invalidError: false };
exactMath.add(Infinity, 5, config); //NaN
exactMath.div(10, NaN, config); //NaN
exactMath.formula('hello world', config); //NaN
const exactMath = require('exact-math');
const customError = new Error('Some error message.');
const config = { invalidError: customError };
exactMath.add(Infinity, 5, config); //[Error]: Some error message.
exactMath.div(10, NaN, config); //[Error]: Some error message.
exactMath.formula('hello world', config); //[Error]: Some error message.
const exactMath = require('exact-math');
const config = {
invalidError: ({ error, index, list, callback }) => {
throw error; //the default error
}
};
exactMath.formula('2 * (4/12', config);
exactMath.div('6.66', '5..3', config);
callback property usageconst exactMath = require('exact-math');
exactMath.add(NaN, 10, '3', ({ error, number, string }) => {
if(error) throw error; //[TypeError]: Incorrect argument [0]. The argument cannot be a NaN value.
})
exactMath.mul('236452e3', '2.22', ({ error, number, string }) => {
const result = exactMath.div(string, 10);
})
exactMath.formula('17/4.44', { maxDecimal: 30 }, ({error, number, string})=>{
console.log(error); //null
console.log(number); //3.828828828828829
console.log(string); //'3.828828828828828828828828828829'
});