-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMathCalculator.ts
110 lines (94 loc) · 4.2 KB
/
MathCalculator.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
// MathCalculator.ts
// tsc MathCalculator.ts -t esnext
export class MathCalculator {
static processFormulaVerbose(line: string): void {
try {
const result = MathCalculator.processFormulaString(line);
console.log(`The result of '${line}' is '${result}'`);
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
console.error(`Error: ${errorMessage}`);
}
}
static processFormulaString(line: string): number {
const words = line.split(" ");
return MathCalculator.processFormulaWords(words, 0, words.length - 1);
}
static processFormulaWords(words: string[], startIndex: number, endIndex: number): number {
if (endIndex < startIndex) throw new RangeError("Invalid index: endIndex < startIndex");
let currentOperator: string | null = null;
let result: number | null = null;
for (let currentIndex = startIndex; currentIndex <= endIndex; currentIndex++) {
const word = words[currentIndex];
const isNumber = !isNaN(parseFloat(word));
if (isNumber || word === "(") {
let number: number;
if (word === "(") {
let depth = 0;
let closingIndex = -1;
for (let searchClosingIndex = currentIndex; searchClosingIndex <= endIndex; searchClosingIndex++) {
if (words[searchClosingIndex] === "(") depth++;
else if (words[searchClosingIndex] === ")") depth--;
if (words[searchClosingIndex] === ")" && depth === 0) {
closingIndex = searchClosingIndex;
break;
}
}
if (closingIndex === -1) {
throw new Error("Invalid input: no closing parenthesis");
}
number = MathCalculator.processFormulaWords(words, currentIndex + 1, closingIndex - 1);
currentIndex = closingIndex;
} else {
number = parseFloat(word);
}
if (currentOperator === null) {
if (result !== null) {
throw new Error("Invalid input: operator expected");
}
result = number;
} else if (currentOperator === "sqrt") {
result = Math.sqrt(number);
} else if (result !== null) {
switch (currentOperator) {
case "+":
result += number;
break;
case "-":
result -= number;
break;
case "*":
result *= number;
break;
case "/":
if (number === 0) throw new Error("Division by zero");
result /= number;
break;
case "^":
result = Math.pow(result, number);
break;
case "%":
result %= number;
break;
default:
throw new Error(`Invalid operator: '${currentOperator}'`);
}
} else {
throw new Error("Invalid input: no result available");
}
currentOperator = null;
} else if (["+", "-", "*", "/", "^", "%", "sqrt"].includes(word)) {
if (currentOperator !== null) {
throw new Error(`Invalid input: operator '${currentOperator}' already set`);
}
currentOperator = word;
} else {
throw new Error(`Invalid input: '${word}' is not a number or operator`);
}
}
if (result === null) {
throw new Error("Invalid input: no result computed");
}
return result;
}
}