Created
February 14, 2023 07:37
-
-
Save linnil1/2714219a333f8a823980ea20ab865958 to your computer and use it in GitHub Desktop.
Calculator made by python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from typing import Any, Iterable | |
from operator import add, sub, mul, truediv, neg | |
op_func: dict[str, Any] = {"+": add, "-": sub, "*": mul, "/": truediv, "**": pow, "--": neg} | |
op_param: dict[str, int] = {"+": 2, "-": 2, "*": 2, "/": 2, "**": 2, "--": 1} | |
priority: dict[str, int] = {"+": 0, "-": 0, "*": 2, "/": 2, "**": 5, "--": 4} | |
op_set = ["**", "*", "+", "-", "/", "(", ")"] | |
num_set = "0123456789." | |
Item = int | float | str | |
def isNumeric(item: Item) -> bool: | |
return isinstance(item, float) or isinstance(item, int) | |
def str2Infix(query_string: str) -> Iterable[Item]: | |
i = 0 | |
prev_i = 0 | |
while i < len(query_string): | |
# operator | |
prev_i = i | |
for op in op_set: | |
if query_string[i:].startswith(op): | |
yield op | |
i += len(op) | |
# number | |
num_str = "" | |
while i < len(query_string) and query_string[i] in num_set: | |
num_str += query_string[i] | |
i += 1 | |
if num_str: | |
yield float(num_str) | |
# space | |
while i < len(query_string) and query_string[i] == " ": | |
i += 1 | |
# cannot go forward | |
assert prev_i != i | |
def infixCheckOp(items: Iterable[Item], prev_op: str | None = None) -> Iterable[Item]: | |
prev: Item = "+" | |
for item in items: | |
assert isNumeric(item) or item in op_func | |
# split minus and sign | |
if not isNumeric(prev) and (item == "+" or item == "-"): | |
if item == "-": | |
yield "--" | |
# also check () matchness | |
# treat () as numeric | |
elif item == "(": | |
assert not isNumeric(prev) | |
yield item | |
yield from infixCheckOp(items, "(") | |
prev = 0 | |
elif item == ")": | |
assert isNumeric(prev) | |
assert prev_op == "(" | |
yield item | |
return | |
# basic rule: num + operator + num | |
elif ((not isNumeric(prev) and isNumeric(item)) or | |
( isNumeric(prev) and not isNumeric(item))): | |
yield item | |
prev = item | |
# error | |
else: | |
assert False | |
assert isNumeric(prev) | |
def infix2Sffuix(items: Iterable[Item]) -> Iterable[Item]: | |
stack_op: list[str] = [] | |
for item in items: | |
if item == "(": | |
yield from infix2Sffuix(items) | |
elif item == ")": | |
break | |
elif isNumeric(item): | |
yield item | |
else: | |
assert isinstance(item, str) | |
while stack_op and priority[item] <= priority[stack_op[-1]] and item != "--": | |
yield stack_op.pop() | |
stack_op.append(item) | |
yield from reversed(stack_op) | |
def calcSuffix(items: Iterable[Item]) -> float: | |
stack: list[int | float] = [] | |
k = 0 | |
for item in items: | |
if not isNumeric(item): | |
assert isinstance(item, str) | |
if op_param[item] == 1: | |
stack[-1] = op_func[item](stack[-1]) | |
elif op_param[item] == 2: | |
stack[-2] = op_func[item](stack[-2], stack[-1]) | |
stack.pop() | |
else: | |
assert False | |
else: | |
assert isinstance(item, (int, float)) | |
stack.append(item) | |
assert len(stack) == 1 | |
return stack[-1] | |
def main(query: str) -> float: | |
items = str2Infix(query) | |
items = infixCheckOp(iter(items)) | |
items = infix2Sffuix(iter(items)) | |
result = calcSuffix(items) | |
return result | |
if __name__ == "__main__": | |
# s = "-7*5/2+(3* 1**-2+5)-8" | |
# s = "3 * -1 ** 2 + 2 ** -1" | |
# s = "3 * -1 ** 2 + 3 + 2 ** -1 + 1 + 1 + (2 + 3) + 5" | |
s = "3 * -1 + -1 ** 2" | |
print(s) | |
print("predit", main(s)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment