|
@@ -1,69 +1,231 @@
|
|
|
+import Decimal from "decimal.js";
|
|
|
+import { ElMessage } from "element-plus";
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
class Counter {
|
|
|
+ private result: Decimal;
|
|
|
+
|
|
|
constructor() {
|
|
|
- this.result = 0;
|
|
|
+ this.result = new Decimal(0);
|
|
|
}
|
|
|
|
|
|
|
|
|
- addition(val) {
|
|
|
- this.result += val;
|
|
|
+ addition(val: number | string): this {
|
|
|
+ this.result = this.result.plus(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
- subtraction(val) {
|
|
|
- this.result -= val;
|
|
|
+ subtraction(val: number | string): this {
|
|
|
+ this.result = this.result.minus(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
- multiplication(val) {
|
|
|
- this.result *= val;
|
|
|
+ multiplication(val: number | string): this {
|
|
|
+ this.result = this.result.times(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
- division(val) {
|
|
|
- this.result /= val;
|
|
|
+ division(val: number | string): this {
|
|
|
+ if (new Decimal(val).isZero()) {
|
|
|
+ throw new Error("除数不能为零");
|
|
|
+ }
|
|
|
+ this.result = this.result.dividedBy(new Decimal(val));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
- calculate(expression) {
|
|
|
+ calculate(expression: string): this {
|
|
|
const tokens = this.tokenize(expression);
|
|
|
const parsedExpression = this.parse(tokens);
|
|
|
- this.result = this.evaluate(parsedExpression);
|
|
|
+ this.result = new Decimal(this.evaluate(parsedExpression));
|
|
|
return this;
|
|
|
}
|
|
|
|
|
|
|
|
|
- get() {
|
|
|
- return this.result;
|
|
|
+ get(): number {
|
|
|
+ return this.result.toNumber();
|
|
|
}
|
|
|
|
|
|
|
|
|
- tokenize(expression) {
|
|
|
- return expression.match(/(\d+(\.\d+)?|[-+*/()])/g);
|
|
|
+ private tokenize(expression: string): Array<string> {
|
|
|
+
|
|
|
+ return expression.match(/-?\d+(\.\d+)?|[-+*/()]/g) || [];
|
|
|
}
|
|
|
|
|
|
|
|
|
- parse(tokens) {
|
|
|
- const output = [];
|
|
|
- const operators = [];
|
|
|
- const precedence = {
|
|
|
+ private parse(tokens: Array<string>): Array<Decimal | string> {
|
|
|
+ const output: Array<Decimal | string> = [];
|
|
|
+ const operators: Array<string> = [];
|
|
|
+ const precedence: { [key: string]: number } = {
|
|
|
"+": 1,
|
|
|
"-": 1,
|
|
|
"*": 2,
|
|
|
"/": 2
|
|
|
};
|
|
|
|
|
|
- for (const token of tokens) {
|
|
|
- if (!isNaN(token)) {
|
|
|
- output.push(Number(token));
|
|
|
+ for (let i = 0; i < tokens.length; i++) {
|
|
|
+ const token = tokens[i];
|
|
|
+
|
|
|
+
|
|
|
+ if (i > 0 && this.isOperator(token) && this.isOperator(tokens[i - 1])) {
|
|
|
+ this.showWarning("公式错误");
|
|
|
+ return [];
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!isNaN(Number(token))) {
|
|
|
+ output.push(new Decimal(token));
|
|
|
} else if (token === "(") {
|
|
|
operators.push(token);
|
|
|
} else if (token === ")") {
|
|
|
while (operators.length && operators[operators.length - 1] !== "(") {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
operators.pop();
|
|
|
} else {
|
|
@@ -71,50 +233,67 @@ class Counter {
|
|
|
operators.length &&
|
|
|
precedence[operators[operators.length - 1]] >= precedence[token]
|
|
|
) {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
operators.push(token);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
while (operators.length) {
|
|
|
- output.push(operators.pop());
|
|
|
+ output.push(operators.pop()!);
|
|
|
}
|
|
|
|
|
|
return output;
|
|
|
}
|
|
|
|
|
|
+
|
|
|
+ private isOperator(token: string): boolean {
|
|
|
+ return ["+", "-", "*", "/"].includes(token);
|
|
|
+ }
|
|
|
+
|
|
|
+ private showWarning(message: string): void {
|
|
|
+
|
|
|
+
|
|
|
+ ElMessage({
|
|
|
+ message: message,
|
|
|
+ type: "warning"
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
|
|
|
- evaluate(parsedExpression) {
|
|
|
- const stack = [];
|
|
|
+ private evaluate(parsedExpression: Array<Decimal | string>): number {
|
|
|
+ const stack: Array<Decimal> = [];
|
|
|
|
|
|
for (const token of parsedExpression) {
|
|
|
- if (typeof token === "number") {
|
|
|
+ if (token instanceof Decimal) {
|
|
|
stack.push(token);
|
|
|
} else {
|
|
|
- const b = stack.pop();
|
|
|
- const a = stack.pop();
|
|
|
+ const b = stack.pop()!;
|
|
|
+ const a = stack.pop()!;
|
|
|
switch (token) {
|
|
|
case "+":
|
|
|
- stack.push(a + b);
|
|
|
+ stack.push(a.plus(b));
|
|
|
break;
|
|
|
case "-":
|
|
|
- stack.push(a - b);
|
|
|
+ stack.push(a.minus(b));
|
|
|
break;
|
|
|
case "*":
|
|
|
- stack.push(a * b);
|
|
|
+ stack.push(a.times(b));
|
|
|
break;
|
|
|
case "/":
|
|
|
- stack.push(a / b);
|
|
|
+ if (b.isZero()) {
|
|
|
+ this.showWarning("除数不能为零");
|
|
|
+ throw new Error("除数不能为零");
|
|
|
+ }
|
|
|
+ stack.push(a.dividedBy(b));
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- return stack[0];
|
|
|
+ return stack[0].toNumber();
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
|
|
|
|
|
|
|