Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 123 additions & 25 deletions calculator.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import math
import re

class Calculator:
def __init__(self):
# Stores variables and memory operations
Expand All @@ -6,67 +9,162 @@ def __init__(self):

def add(self, a, b):
"""Add two numbers."""
# TODO: Implement this
pass
return a + b

def subtract(self, a, b):
"""Subtract b from a."""
# TODO: Implement this
pass
return a - b

def multiply(self, a, b):
"""Multiply two numbers."""
# TODO: Implement this
pass
return a * b

def divide(self, a, b):
"""Divide a by b, handle divide-by-zero gracefully."""
# TODO: Implement this
pass
if b == 0:
return "Error: Division by zero"
return a / b

def store_in_memory(self, value):
"""Store a number in memory."""
# TODO: Implement this
pass
self.memory = value

def recall_memory(self):
"""Return the last stored value."""
# TODO: Implement this
pass
return self.memory

def clear_memory(self):
"""Clear the stored memory value."""
# TODO: Implement this
pass
self.memory = 0

def assign_variable(self, name, value):
"""Assign a variable (like x = 5)."""
# TODO: Implement this
pass
self.variables[name] = value

def _tokenize(self, expr):
"""Convert expression string into tokens."""
# Remove spaces
expr = expr.replace(" ", "")
# Add spaces around operators and parentheses
expr = re.sub(r'([+\-*/()^])', r' \1 ', expr)
# Split and filter out empty strings
tokens = [token for token in expr.split() if token]
return tokens

def _infix_to_postfix(self, tokens):
"""Convert infix notation to postfix using Shunting Yard algorithm."""
precedence = {'+': 1, '-': 1, '*': 2, '/': 2, '^': 3}
right_associative = {'^'}
output = []
operator_stack = []

for token in tokens:
if token.replace('.', '', 1).isdigit() or token.replace('-', '', 1).replace('.', '', 1).isdigit():
output.append(float(token))
elif token in self.variables:
output.append(float(self.variables[token]))
elif token in precedence:
while (operator_stack and
operator_stack[-1] != '(' and
operator_stack[-1] in precedence and
(precedence[operator_stack[-1]] > precedence[token] or
(precedence[operator_stack[-1]] == precedence[token] and token not in right_associative))):
output.append(operator_stack.pop())
operator_stack.append(token)
elif token == '(':
operator_stack.append(token)
elif token == ')':
while operator_stack and operator_stack[-1] != '(':
output.append(operator_stack.pop())
if operator_stack and operator_stack[-1] == '(':
operator_stack.pop() # Remove the '('
else:
raise ValueError("Mismatched parentheses")

while operator_stack:
if operator_stack[-1] in '()':
raise ValueError("Mismatched parentheses")
output.append(operator_stack.pop())

return output

def _evaluate_postfix(self, postfix_tokens):
"""Evaluate postfix expression."""
stack = []
for token in postfix_tokens:
if isinstance(token, float):
stack.append(token)
elif token == '+':
if len(stack) < 2:
raise ValueError("Invalid expression")
b, a = stack.pop(), stack.pop()
stack.append(self.add(a, b))
elif token == '-':
if len(stack) < 2:
raise ValueError("Invalid expression")
b, a = stack.pop(), stack.pop()
stack.append(self.subtract(a, b))
elif token == '*':
if len(stack) < 2:
raise ValueError("Invalid expression")
b, a = stack.pop(), stack.pop()
stack.append(self.multiply(a, b))
elif token == '/':
if len(stack) < 2:
raise ValueError("Invalid expression")
b, a = stack.pop(), stack.pop()
result = self.divide(a, b)
if isinstance(result, str): # Error message
raise ValueError(result)
stack.append(result)
elif token == '^':
if len(stack) < 2:
raise ValueError("Invalid expression")
b, a = stack.pop(), stack.pop()
stack.append(self.power(a, b))
else:
raise ValueError(f"Unknown token: {token}")

if len(stack) != 1:
raise ValueError("Invalid expression")
return stack[0]

def evaluate_expression(self, expr):
"""
Evaluate a mathematical expression string.
Example: "2 + 3 * (4 - 1)" or "x * 5" after x = 3
Should handle parentheses and variable substitution.
"""
# TODO: Implement safely (without eval)
pass
try:
tokens = self._tokenize(expr)
postfix = self._infix_to_postfix(tokens)
result = self._evaluate_postfix(postfix)
return result
except Exception as e:
return f"Error: {str(e)}"

def sqrt(self, x):
"""Return the square root of x."""
# TODO: Implement this
pass
if x < 0:
return "Error: Cannot take square root of negative number"
return math.sqrt(x)

def power(self, base, exp):
"""Return base raised to the power of exp."""
# TODO: Implement this
pass
try:
return base ** exp
except OverflowError:
return "Error: Result too large"

def factorial(self, n):
"""Return factorial of n."""
# TODO: Implement recursively
pass
if not isinstance(n, int):
return "Error: Factorial is only defined for integers"
if n < 0:
return "Error: Factorial is not defined for negative numbers"
if n == 0 or n == 1:
return 1
return n * self.factorial(n - 1)


if __name__ == "__main__":
Expand All @@ -76,4 +174,4 @@ def factorial(self, n):
print(calc.divide(10, 0)) # Expect "Error: Division by zero"
print(calc.evaluate_expression("2 + 3 * (4 - 1)")) # Expect 11
calc.assign_variable("x", 7)
print(calc.evaluate_expression("x * 2")) # Expect 14
print(calc.evaluate_expression("x * 2")) # Expect 14
2 changes: 1 addition & 1 deletion test.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
print("this is initial commit")
print("this is initial commit")