Get around floating point precision of JavaScript fixes #5
Fix `equation` not working on parentheses wrapped variables Fixed `parseExpression` not working correctly on nested function operators
This commit is contained in:
40
lib/index.js
40
lib/index.js
@ -49,7 +49,11 @@ let Equation = {
|
||||
let stack = parseExpression(expression);
|
||||
let variables = [];
|
||||
|
||||
stack.forEach(a => {
|
||||
stack.forEach(function varCheck(a) {
|
||||
if (Array.isArray(a)) {
|
||||
return a.forEach(varCheck);
|
||||
}
|
||||
|
||||
if (typeof a === 'string' && !_.isNumber(a) &&
|
||||
!operators[a] && a === a.toLowerCase()) {
|
||||
// grouped variables like (y) need to have their parantheses removed
|
||||
@ -125,23 +129,32 @@ const parseExpression = expression => {
|
||||
}
|
||||
|
||||
// it's probably a function with a length more than one
|
||||
if (!_.isNumber(cur) && !operators[cur] && cur !== '.') {
|
||||
if (!_.isNumber(cur) && !operators[cur] && cur !== '.' &&
|
||||
cur !== '(' && cur !== ')') {
|
||||
|
||||
record += cur;
|
||||
} else if (record.length) {
|
||||
stack.push(record, cur);
|
||||
record = '';
|
||||
} else if (_.isNumber(stack[stack.length - 1]) &&
|
||||
} else if (_.isNumber(stack[past]) &&
|
||||
(_.isNumber(cur) || cur === '.')) {
|
||||
|
||||
stack[stack.length - 1] += cur;
|
||||
} else if (stack[past] === '-') {
|
||||
const beforeSign = stack[stack.length - 2];
|
||||
stack[past] += cur;
|
||||
|
||||
// negation sign
|
||||
} else if (stack[past] === '-') {
|
||||
const beforeSign = stack[past - 1];
|
||||
|
||||
// 2 / -5 is OK, pass
|
||||
if (operators[beforeSign]) {
|
||||
stack[past] += cur;
|
||||
|
||||
// (2+1) - 5 becomes (2+1) + -5
|
||||
} else if (beforeSign === ')') {
|
||||
stack[past] = '+';
|
||||
stack.push(`-${cur}`);
|
||||
|
||||
// 2 - 5 is also OK, pass
|
||||
} else if (_.isNumber(beforeSign)) {
|
||||
stack.push(cur);
|
||||
} else {
|
||||
@ -272,12 +285,13 @@ const evaluate = stack => {
|
||||
if (!op) {
|
||||
return stack[0];
|
||||
}
|
||||
|
||||
const { left } = formatInfo(op);
|
||||
|
||||
let leftArguments = stack.slice(0, left),
|
||||
rightArguments = stack.slice(left + 1);
|
||||
|
||||
return operators[op].fn(...leftArguments, ...rightArguments);
|
||||
return fixFloat(operators[op].fn(...leftArguments, ...rightArguments));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -315,4 +329,16 @@ const replaceConstants = expression => {
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Fixes JavaScript's floating point precisions - Issue #5
|
||||
*
|
||||
* @param {Number} number
|
||||
* The number to fix
|
||||
* @return {Number}
|
||||
* Fixed number
|
||||
*/
|
||||
const fixFloat = number => {
|
||||
return +number.toFixed(15);
|
||||
};
|
||||
|
||||
export default Equation;
|
||||
|
@ -88,5 +88,15 @@ export default {
|
||||
fn: Math.cot,
|
||||
format: '10',
|
||||
precedence: -1
|
||||
},
|
||||
'round': {
|
||||
fn: Math.round,
|
||||
format: '10',
|
||||
precedence: -1
|
||||
},
|
||||
'floor': {
|
||||
fn: Math.floor,
|
||||
format: '10',
|
||||
precedence: -1
|
||||
}
|
||||
};
|
||||
|
Reference in New Issue
Block a user