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 */ 15 16const OperatorLevels = { 17 '+': 0, 18 '-': 0, 19 '*': 1, 20 '/': 1, 21} 22 23const OperatorHandlers = { 24 '+': (firstOperand, secondOperand) => (parseFloat(firstOperand) + parseFloat(secondOperand)).toFixed(getFloatNum(firstOperand, secondOperand, '+')), 25 '-': (firstOperand, secondOperand) => (firstOperand - secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '-')), 26 '*': (firstOperand, secondOperand) => (firstOperand * secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '*')), 27 '/': (firstOperand, secondOperand) => (firstOperand / secondOperand).toFixed(getFloatNum(firstOperand, secondOperand, '/')), 28} 29 30function getFloatNum(firstOperand, secondOperand, oprate) { 31 let result = 0 32 let oneString = (new String(firstOperand)).toString() 33 let otherString = (new String(secondOperand)).toString() 34 let firstNum = 0 35 if (oneString.indexOf('.') !== -1) { 36 firstNum = oneString.split('.')[1].length 37 } 38 let secondNum = 0 39 if (otherString.indexOf('.') !== -1) { 40 secondNum = otherString.split('.')[1].length 41 } 42 if (oprate === '+' || oprate === '-') { 43 result = Math.max(firstNum, secondNum) 44 } 45 if (oprate === '*') { 46 result = firstNum + secondNum 47 } 48 if (oprate === '/') { 49 result = (firstNum + otherString.length) > 3 ? (firstNum + otherString.length) : 3 50 } 51 return result 52} 53 54function calcSuffixExpression(expression) { 55 const numberStack = [] 56 57 58 while (expression.length) { 59 let element = expression.shift() 60 if (!isOperator(element)) { 61 numberStack.push(element) 62 } else { 63 const firstStackElement = numberStack.pop() 64 const secondStackElement = numberStack.pop() 65 const result = OperatorHandlers[element](secondStackElement, firstStackElement) 66 if (result.length > 15) { 67 numberStack.push(parseFloat(result).toExponential()) 68 } else { 69 numberStack.push(result) 70 } 71 } 72 } 73 return numberStack[0] 74} 75 76function toSuffixExpression(expression) { 77 const operatorStack = [] 78 const suffixExpression = [] 79 let topOperator 80 for (let index = 0, size = expression.length; index < size; ++index) { 81 const element = expression[index] 82 if (element === '(') { 83 operatorStack.push(element) 84 continue 85 } 86 if (element === ')') { 87 if (operatorStack.length) { 88 let operator = operatorStack.pop() 89 while (operator !== '(') { 90 suffixExpression.push(operator) 91 operator = operatorStack.pop() 92 } 93 } 94 continue 95 } 96 if (isOperator(element)) { 97 if (!operatorStack.length) { 98 operatorStack.push(element) 99 } else { 100 topOperator = operatorStack[operatorStack.length - 1] 101 if (!isGrouping(topOperator) && !isPrioritized(element, topOperator)) { 102 while (operatorStack.length) { 103 suffixExpression.push(operatorStack.pop()) 104 } 105 } 106 operatorStack.push(element) 107 } 108 continue 109 } 110 suffixExpression.push(element) 111 } 112 while (operatorStack.length) { 113 suffixExpression.push(operatorStack.pop()) 114 } 115 return suffixExpression 116} 117 118function parseInfixExpression(inputContent) { 119 const size = inputContent.length 120 const lastIndex = size - 1 121 let singleChar = '' 122 const expression = [] 123 for (let index = 0; index < size; index++) { 124 const element = inputContent[index] 125 if (isGrouping(element)) { 126 if (singleChar !== '') { 127 expression.push(singleChar) 128 singleChar = '' 129 } 130 expression.push(element) 131 } else if (isOperator(element)) { 132 if (isSymbol(element) && (index === 0 || inputContent[index - 1] === '(')) { 133 singleChar += element 134 } else { 135 if (singleChar !== '') { 136 expression.push(singleChar) 137 singleChar = '' 138 } 139 if (index !== lastIndex) { 140 expression.push(element) 141 } 142 } 143 } else { 144 singleChar += element 145 } 146 if (index === lastIndex && singleChar !== '') { 147 expression.push(singleChar) 148 } 149 } 150 return expression 151} 152 153function isPrioritized(firstOperator, secondOperator) { 154 return OperatorLevels[firstOperator] > OperatorLevels[secondOperator] 155} 156 157export function isOperator(operator) { 158 return ( 159 operator === '+' || operator === '-' || operator === '*' || operator === '/' 160 ) 161} 162 163function isSymbol(symbol) { 164 return symbol === '+' || symbol === '-' 165} 166 167function isGrouping(operator) { 168 return operator === '(' || operator === ')' 169} 170 171export function calc(inputContent) { 172 const infixExpression = parseInfixExpression(inputContent) 173 const suffixExpression = toSuffixExpression(infixExpression) 174 return calcSuffixExpression(suffixExpression) 175}