|
|
|
import math |
|
from typing import Union, List, Any |
|
from .utils import logger |
|
|
|
Number = Union[int, float] |
|
|
|
class MathTools: |
|
"""Simple math tools for basic calculations and utilities""" |
|
|
|
@staticmethod |
|
def add(a: Number, b: Number) -> Number: |
|
"""Return the sum of a and b""" |
|
return a + b |
|
|
|
@staticmethod |
|
def subtract(a: Number, b: Number) -> Number: |
|
"""Return the difference of a and b""" |
|
return a - b |
|
|
|
@staticmethod |
|
def multiply(a: Number, b: Number) -> Number: |
|
"""Return the product of a and b""" |
|
return a * b |
|
|
|
@staticmethod |
|
def divide(a: Number, b: Number) -> Union[Number, str]: |
|
"""Return the division of a by b, handle division by zero""" |
|
if b == 0: |
|
return 'Error: Division by zero' |
|
return a / b |
|
|
|
@staticmethod |
|
def power(base: Number, exponent: Number) -> Number: |
|
"""Return base raised to the power of exponent""" |
|
return base ** exponent |
|
|
|
@staticmethod |
|
def factorial(n: int) -> Union[int, str]: |
|
"""Return factorial of n (non-negative integer)""" |
|
if not isinstance(n, int) or n < 0: |
|
return 'Error: Input must be a non-negative integer' |
|
if n == 0 or n == 1: |
|
return 1 |
|
result = 1 |
|
for i in range(2, n + 1): |
|
result *= i |
|
return result |
|
|
|
@staticmethod |
|
def square_root(n: Number) -> Union[float, str]: |
|
"""Return square root of n""" |
|
if n < 0: |
|
return 'Error: Cannot calculate square root of negative number' |
|
return math.sqrt(n) |
|
|
|
@staticmethod |
|
def percentage(part: Number, whole: Number) -> Union[float, str]: |
|
"""Calculate percentage: (part/whole) * 100""" |
|
if whole == 0: |
|
return 'Error: Cannot calculate percentage with zero denominator' |
|
return (part / whole) * 100 |
|
|
|
@staticmethod |
|
def average(numbers: List[Number]) -> Union[float, str]: |
|
"""Calculate average of a list of numbers""" |
|
if not numbers: |
|
return 'Error: Cannot calculate average of empty list' |
|
return sum(numbers) / len(numbers) |
|
|
|
@staticmethod |
|
def round_number(n: Number, decimals: int = 2) -> Number: |
|
"""Round number to specified decimal places""" |
|
return round(n, decimals) |
|
|
|
@staticmethod |
|
def absolute(n: Number) -> Number: |
|
"""Return absolute value of n""" |
|
return abs(n) |
|
|
|
@staticmethod |
|
def min_value(numbers: List[Number]) -> Union[Number, str]: |
|
"""Find minimum value in list""" |
|
if not numbers: |
|
return 'Error: Cannot find minimum of empty list' |
|
return min(numbers) |
|
|
|
@staticmethod |
|
def max_value(numbers: List[Number]) -> Union[Number, str]: |
|
"""Find maximum value in list""" |
|
if not numbers: |
|
return 'Error: Cannot find maximum of empty list' |
|
return max(numbers) |
|
|
|
@staticmethod |
|
def calculate_compound_interest(principal: Number, rate: Number, time: Number, compounds_per_year: int = 1) -> float: |
|
""" |
|
Calculate compound interest |
|
Formula: A = P(1 + r/n)^(nt) |
|
""" |
|
return principal * (1 + rate/compounds_per_year) ** (compounds_per_year * time) |
|
|
|
@staticmethod |
|
def solve_quadratic(a: Number, b: Number, c: Number) -> Union[tuple, str]: |
|
""" |
|
Solve quadratic equation ax² + bx + c = 0 |
|
Returns tuple of solutions or error message |
|
""" |
|
if a == 0: |
|
return 'Error: Not a quadratic equation (a cannot be 0)' |
|
|
|
discriminant = b**2 - 4*a*c |
|
|
|
if discriminant < 0: |
|
return 'Error: No real solutions (negative discriminant)' |
|
elif discriminant == 0: |
|
solution = -b / (2*a) |
|
return (solution, solution) |
|
else: |
|
sqrt_discriminant = math.sqrt(discriminant) |
|
solution1 = (-b + sqrt_discriminant) / (2*a) |
|
solution2 = (-b - sqrt_discriminant) / (2*a) |
|
return (solution1, solution2) |
|
|
|
|
|
def add(a: Number, b: Number) -> Number: |
|
"""Add two numbers""" |
|
return MathTools.add(a, b) |
|
|
|
def subtract(a: Number, b: Number) -> Number: |
|
"""Subtract two numbers""" |
|
return MathTools.subtract(a, b) |
|
|
|
def multiply(a: Number, b: Number) -> Number: |
|
"""Multiply two numbers""" |
|
return MathTools.multiply(a, b) |
|
|
|
def divide(a: Number, b: Number) -> Union[Number, str]: |
|
"""Divide two numbers""" |
|
return MathTools.divide(a, b) |
|
|
|
def power(base: Number, exponent: Number) -> Number: |
|
"""Raise base to power of exponent""" |
|
return MathTools.power(base, exponent) |
|
|
|
def factorial(n: int) -> Union[int, str]: |
|
"""Calculate factorial of n""" |
|
return MathTools.factorial(n) |
|
|
|
def square_root(n: Number) -> Union[float, str]: |
|
"""Calculate square root""" |
|
return MathTools.square_root(n) |
|
|
|
def percentage(part: Number, whole: Number) -> Union[float, str]: |
|
"""Calculate percentage""" |
|
return MathTools.percentage(part, whole) |
|
|
|
def average(numbers: List[Number]) -> Union[float, str]: |
|
"""Calculate average of numbers""" |
|
return MathTools.average(numbers) |
|
|
|
def calculate_expression(expression: str) -> Union[Number, str]: |
|
""" |
|
Safely evaluate mathematical expressions |
|
WARNING: Only use with trusted input |
|
""" |
|
try: |
|
|
|
allowed_chars = set('0123456789+-*/().^ ') |
|
if not all(c in allowed_chars for c in expression.replace('**', '^')): |
|
return 'Error: Invalid characters in expression' |
|
|
|
|
|
safe_expression = expression.replace('^', '**') |
|
|
|
|
|
result = eval(safe_expression) |
|
return result |
|
except ZeroDivisionError: |
|
return 'Error: Division by zero in expression' |
|
except Exception as e: |
|
return f'Error: Invalid expression - {str(e)}' |
|
|
|
|
|
if __name__ == "__main__": |
|
|
|
print("Basic Operations:") |
|
print(f"5 + 3 = {add(5, 3)}") |
|
print(f"10 - 4 = {subtract(10, 4)}") |
|
print(f"6 * 7 = {multiply(6, 7)}") |
|
print(f"15 / 3 = {divide(15, 3)}") |
|
print(f"2^8 = {power(2, 8)}") |
|
|
|
print("\nAdvanced Operations:") |
|
print(f"√16 = {square_root(16)}") |
|
print(f"5! = {factorial(5)}") |
|
print(f"Average of [1,2,3,4,5] = {average([1,2,3,4,5])}") |
|
percent_result = percentage(25, 100) |
|
if isinstance(percent_result, float): |
|
print(f"25% of 200 = {percent_result * 200 / 100}") |
|
else: |
|
print(f"25% of 200 = {percent_result}") |
|
|
|
print("\nQuadratic Equation (x² - 5x + 6 = 0):") |
|
solutions = MathTools.solve_quadratic(1, -5, 6) |
|
print(f"Solutions: {solutions}") |
|
|