1/* 2 * Copyright (c) 2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15const OPERATORLEVELS = { 16 '+': 0, 17 '-': 0, 18 '*': 1, 19 '/': 1, 20} 21 22const OPERATORHANDLERS = { 23 '+': (firstOperand, secondOperand) => (parseFloat(firstOperand) + parseFloat(secondOperand)).toFixed(getFloatNum(firstOperand, secondOperand, '+')), 24 '-': (firstOperand, secondOperand) => (firstOperand - secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '-')), 25 '*': (firstOperand, secondOperand) => (firstOperand * secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '*')), 26 '/': (firstOperand, secondOperand) => (firstOperand / secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '/')), 27} 28 29function getFloatNum(firstOperand, secondOperand, oprate) { 30 let result = 0 31 let oneString = (new String(firstOperand)).toString() 32 let otherString = (new String(secondOperand)).toString() 33 let firstNum = 0 34 if (oneString.indexOf('.') !== -1) { 35 firstNum = oneString.split('.')[1].length 36 } 37 let secondNum = 0 38 if (otherString.indexOf('.') !== -1) { 39 secondNum = otherString.split('.')[1].length 40 } 41 if (oprate === '+' || oprate === '-') { 42 result = Math.max(firstNum, secondNum) 43 } 44 if (oprate === '*') { 45 result = firstNum + secondNum 46 } 47 if (oprate === '/') { 48 result = (firstNum + otherString.length) > 3 ? (firstNum + otherString.length) : 3 49 } 50 return result 51} 52 53function calcSuffixExpression(expression) { 54 const numberStack = [] 55 while (expression.length) { 56 let element = expression.shift() 57 if (!isOperator(element)) { 58 numberStack.push(element) 59 } else { 60 const firstStackElement = numberStack.pop() 61 const secondStackElement = numberStack.pop() 62 const result = OPERATORHANDLERS[element](secondStackElement, firstStackElement) 63 if (result.length > 15) { 64 numberStack.push(parseFloat(result).toExponential()) 65 } else { 66 numberStack.push(result) 67 } 68 } 69 } 70 return numberStack[0] 71} 72 73function toSuffixExpression(expression) { 74 const operatorStack = [] 75 const suffixExpression = [] 76 let topOperator 77 for (let index = 0, size = expression.length; index < size; ++index) { 78 const element = expression[index] 79 if (element === '(') { 80 operatorStack.push(element) 81 continue 82 } 83 if (element === ')') { 84 if (operatorStack.length) { 85 let operator = operatorStack.pop() 86 while (operator !== '(') { 87 suffixExpression.push(operator) 88 operator = operatorStack.pop() 89 } 90 } 91 continue 92 } 93 if (isOperator(element)) { 94 if (!operatorStack.length) { 95 operatorStack.push(element) 96 } else { 97 topOperator = operatorStack[operatorStack.length - 1] 98 if (!isGrouping(topOperator) && !isPrioritized(element, topOperator)) { 99 while (operatorStack.length && !isPrioritized(element, operatorStack[operatorStack.length - 1])) { 100 suffixExpression.push(operatorStack.pop()) 101 } 102 } 103 operatorStack.push(element) 104 } 105 continue 106 } 107 suffixExpression.push(element) 108 } 109 while (operatorStack.length) { 110 suffixExpression.push(operatorStack.pop()) 111 } 112 return suffixExpression 113} 114 115function parseInfixExpression(inputContent) { 116 const size = inputContent.length 117 const lastIndex = size - 1 118 let singleChar = '' 119 const expression = [] 120 for (let index = 0; index < size; index++) { 121 const element = inputContent[index] 122 if (isGrouping(element)) { 123 if (singleChar !== '') { 124 expression.push(singleChar) 125 singleChar = '' 126 } 127 expression.push(element) 128 } else if (isOperator(element)) { 129 if (isSymbol(element) && (index === 0 || inputContent[index - 1] === '(')) { 130 singleChar += element 131 } else { 132 if (singleChar !== '') { 133 expression.push(singleChar) 134 singleChar = '' 135 } 136 if (index !== lastIndex) { 137 expression.push(element) 138 } 139 } 140 } else { 141 singleChar += element 142 } 143 if (index === lastIndex && singleChar !== '') { 144 expression.push(singleChar) 145 } 146 } 147 return expression 148} 149 150function isPrioritized(firstOperator, secondOperator) { 151 return OPERATORLEVELS[firstOperator] > OPERATORLEVELS[secondOperator] 152} 153 154export function isOperator(operator) { 155 return ( 156 operator === '+' || operator === '-' || operator === '*' || operator === '/' 157 ) 158} 159 160function isSymbol(symbol) { 161 return symbol === '+' || symbol === '-' 162} 163 164function isGrouping(operator) { 165 return operator === '(' || operator === ')' 166} 167 168export function calc(inputContent) { 169 const infixExpression = parseInfixExpression(inputContent) 170 const suffixExpression = toSuffixExpression(infixExpression) 171 return calcSuffixExpression(suffixExpression) 172}