File size: 7,090 Bytes
c66530c |
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 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
# tools/math_tools.py
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)
# Convenience functions for direct use
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:
# Only allow safe mathematical operations
allowed_chars = set('0123456789+-*/().^ ')
if not all(c in allowed_chars for c in expression.replace('**', '^')):
return 'Error: Invalid characters in expression'
# Replace ^ with ** for Python exponentiation
safe_expression = expression.replace('^', '**')
# Evaluate the expression
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)}'
# Example usage and testing
if __name__ == "__main__":
# Test basic operations
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}")
|