exact-math

In This Documentation

  1. Description
  2. Implementation
  3. Tests
  4. Features
  5. Methods
    a. add, sub, mul, div
    b. formula
    c. round, ceil, floor
    d. pow
  6. config parameter
    a. returnString
    b. decimalChar
    c. divChar
    d. mulChar
    e. eMinus
    f. ePlus
    g. maxDecimal
    h. divideByZeroError
    i. invalidError
  7. callback parameter
  8. Return
  9. Samples

Description

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.

Implementation

with NodeJS

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

with Browser

Add 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>

Tests

> git clone https://github.com/devrafalko/exact-math.git
> cd exact-math
> npm install
> npm test

Features

How it works:

Floating point problem:

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

Big integers and small decimals

const config = { returnString: true };
let result = exactMath.sub('92179342550763210809069221175572', '11779955999989769291989599', config);
//'92179330770807210819299929185973'

let result = exactMath.add('3.00000000000000000015', '12.00000000000000020020', config);
//'15.00000000000000020035'

Arithmetic formulas

Rounding integers and decimals

Methods

add, sub, mul, div

exactMath.add(x, y[, z[, …]][, config][, callback])

add, sub, mul and div methods take the same arguments

x, y

Type: [Number|String]

formula

exactMath.formula(formula[, config][, callback])

round, ceil, floor

exactMath.round(value[, places][, config][, callback])

round, ceil and floor methods take the same arguments

value

Type: [Number|String]

places

Type: [Number] (optional)
Default: 1

places 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

pow

exactMath.pow(value[, power][, config][, callback])

value

Type: [Number|String]

power

Type: [Number] (optional)
Default: 2

config parameter

config

Type: [Object|Boolean] optional
Default: false

[Object] config properties:

returnString

Type: [Boolean]
Default: false

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 the config.returnString parameter to true.
The [String] numerical values passed as the arguments and the [String] result returned by the exact-math are always safe.

decimalChar

Type: [String|Array:string]
Default: ['.', ',']

divChar

Type: [String|Array:string]
Default: ['/', ':', '÷']

mulChar

Type: [String|Array:string]
Default: ['*', 'x', '⋅']

eMinus

Type: [Number]
Default: 7

ePlus

Type: [Number]
Default: 21

maxDecimal

Type: [Number]
Default: 17

divideByZeroError

Type: [Boolean|Error|Function]
Default: false

invalidError

Type: [Boolean|Error|Function]
Default: true

callback parameter

callback

Type: [Function] optional
Default: undefined

Return

Samples

The addition, subtraction, division and multiplication methods usage
const 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'
The formula method usage
const 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
The round, ceil and floor methods usage
const 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
The pow method usage
const 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
The config returnString property set as [Boolean] argument
const 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]
The config returnString property usage
const 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'
The config decimalChar property usage
const 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 .
The config divChar property usage
const 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
The config mulChar property usage
const 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
The config ePlus and eMinus properties usage
const 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'
The config maxDecimal property usage
const 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'
The config divideByZeroError property usage
const 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
The config invalidError property usage
const 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);
The callback property usage
const 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'
});