"""Calculator module providing mathematical calculation functions.
This module contains the Calculator class which provides a comprehensive set of mathematical operations including:
- Constants: pi, e, tau, inf, nan
- Basic arithmetic: add, subtract, multiply, divide, mod
- Power and roots: power, sqrt, cbrt, isqrt
- Distance and norm: dist, hypot
- Trigonometric functions: sin, cos, tan, asin, acos, atan, degrees, radians
- Hyperbolic functions: sinh, cosh, tanh, asinh, acosh, atanh
- Logarithmic and exponential functions: log, ln, log10, log2, log1p, exp, expm1
- Numerical processing: abs, round, floor, ceil, trunc, copysign, frexp, ldexp, modf, remainder, nextafter, ulp, fmod, isclose
- Combinatorics: factorial, gcd, lcm, comb, perm
- Special functions: erf, erfc, gamma, lgamma
- Numerical validation: isfinite, isinf, isnan
- Statistical functions: average, median, mode, standard_deviation, min, max, sum, prod, fsum
- Financial calculations: simple_interest, compound_interest
- Random number generation: random, randint
- Expression evaluation: evaluate (supports expressions combining above functions)
Example:
>>> from toolregistry.hub import Calculator
>>> calc = Calculator()
>>> calc.add(1, 2)
3
>>> calc.evaluate("add(2, 3) * power(2, 3) + sqrt(16)")
44
"""
import math
import random
from typing import Dict, List, Union
[docs]
class Calculator:
"""Performs mathematical calculations.
This class provides a unified interface for a wide range of mathematical operations,
including basic arithmetic, scientific functions, statistical calculations,
financial computations, random number generation, and expression evaluation.
Methods:
Constants:
pi, e, tau, inf, nan
Basic arithmetic:
add, subtract, multiply, divide, mod
Power and roots:
power, sqrt, cbrt, isqrt
Distance and norm:
dist, hypot
Trigonometric functions:
sin, cos, tan, asin, acos, atan, degrees, radians
Hyperbolic functions:
sinh, cosh, tanh, asinh, acosh, atanh
Logarithmic and exponential functions:
log, ln, log10, log2, log1p, exp, expm1
Numerical processing:
abs, round, floor, ceil, trunc, copysign, frexp, ldexp, modf, remainder, nextafter, ulp, fmod, isclose
Combinatorics:
factorial, gcd, lcm, comb, perm
Special functions:
erf, erfc, gamma, lgamma
Numerical validation:
isfinite, isinf, isnan
Statistical functions:
average, median, mode, standard_deviation, min, max, sum, prod, fsum
Financial calculations:
simple_interest, compound_interest
Random number generation:
random, randint
Expression evaluation:
evaluate
"""
# ====== Constant 常数定义 ======
[docs]
@staticmethod
def pi() -> float:
"""Returns the mathematical constant π."""
return math.pi
[docs]
@staticmethod
def e() -> float:
"""Returns the mathematical constant e."""
return math.e
[docs]
@staticmethod
def tau() -> float:
"""Returns the mathematical constant tau (2π)."""
return math.tau
[docs]
@staticmethod
def inf() -> float:
"""Returns positive infinity."""
return math.inf
[docs]
@staticmethod
def nan() -> float:
"""Returns NaN (Not a Number)."""
return math.nan
# ====== Basic arithmetic 基本算术运算 ======
[docs]
@staticmethod
def add(a: float, b: float) -> float:
"""Adds two numbers."""
return a + b
[docs]
@staticmethod
def subtract(a: float, b: float) -> float:
"""Subtracts two numbers."""
return a - b
[docs]
@staticmethod
def multiply(a: float, b: float) -> float:
"""Multiplies two numbers."""
return a * b
[docs]
@staticmethod
def divide(a: float, b: float) -> float:
"""Divides two numbers."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
[docs]
@staticmethod
def mod(a: float, b: float) -> float:
"""Calculates a modulo b."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a % b
# ====== Power and roots 幂和根 ======
[docs]
@staticmethod
def power(base: float, exponent: float) -> float:
"""Raises base to exponent power."""
# No range check needed for power
return base**exponent
[docs]
@staticmethod
def sqrt(x: float) -> float:
"""Calculates square root of a number."""
if x < 0:
raise ValueError("Cannot calculate square root of negative number")
return x**0.5
[docs]
@staticmethod
def cbrt(x: float) -> float:
"""Calculates cube root of a number."""
return math.copysign(abs(x) ** (1 / 3), x)
[docs]
@staticmethod
def isqrt(n: int) -> int:
"""Calculates integer square root of non-negative integer n."""
if n < 0:
raise ValueError("n must be non-negative")
return math.isqrt(n)
# ====== Distance and norm 距离/范数 ======
[docs]
@staticmethod
def dist(p: List[float], q: List[float]) -> float:
"""Calculates Euclidean distance between two points."""
if len(p) != len(q):
raise ValueError("Points must have same dimensions")
return math.dist(p, q)
[docs]
@staticmethod
def hypot(*coordinates: float) -> float:
"""Calculates Euclidean norm (sqrt(sum(x^2)))."""
return math.hypot(*coordinates)
# ====== Trignormetric functions 三角函数 ======
[docs]
@staticmethod
def sin(x: float) -> float:
"""Calculates sine of x (in radians)."""
# No range check needed for sin
return math.sin(x)
[docs]
@staticmethod
def cos(x: float) -> float:
"""Calculates cosine of x (in radians)."""
# No range check needed for cos
return math.cos(x)
[docs]
@staticmethod
def tan(x: float) -> float:
"""Calculates tangent of x (in radians)."""
# No range check needed for tan
return math.tan(x)
[docs]
@staticmethod
def asin(x: float) -> float:
"""Calculates arcsine of x (in radians)."""
if x < -1 or x > 1:
raise ValueError("x must be between -1 and 1")
return math.asin(x)
[docs]
@staticmethod
def acos(x: float) -> float:
"""Calculates arccosine of x (in radians)."""
if x < -1 or x > 1:
raise ValueError("x must be between -1 and 1")
return math.acos(x)
[docs]
@staticmethod
def atan(x: float) -> float:
"""Calculates arctangent of x (in radians)."""
# No range check needed for atan
return math.atan(x)
[docs]
@staticmethod
def degrees(x: float) -> float:
"""Converts angle x from radians to degrees."""
# No range check needed for degrees
return math.degrees(x)
[docs]
@staticmethod
def radians(x: float) -> float:
"""Converts angle x from degrees to radians."""
# No range check needed for radians
return math.radians(x)
# ====== Hyperbolic functions 双曲函数 ======
[docs]
@staticmethod
def sinh(x: float) -> float:
"""Calculates the hyperbolic sine of x."""
# No range check needed for sinh
return math.sinh(x)
[docs]
@staticmethod
def cosh(x: float) -> float:
"""Calculates the hyperbolic cosine of x."""
# No range check needed for cosh
return math.cosh(x)
[docs]
@staticmethod
def tanh(x: float) -> float:
"""Calculates the hyperbolic tangent of x."""
# No range check needed for tanh
return math.tanh(x)
[docs]
@staticmethod
def asinh(x: float) -> float:
"""Calculates the inverse hyperbolic sine of x."""
# No range check needed for asinh
return math.asinh(x)
[docs]
@staticmethod
def acosh(x: float) -> float:
"""Calculates the inverse hyperbolic cosine of x. x must be >= 1."""
if x < 1:
raise ValueError("x must be >= 1 for acosh")
return math.acosh(x)
[docs]
@staticmethod
def atanh(x: float) -> float:
"""Calculates the inverse hyperbolic tangent of x. |x| must be less than 1."""
if abs(x) >= 1:
raise ValueError("Absolute value of x must be less than 1 for atanh")
return math.atanh(x)
# ====== Logarithmic and exponential functions 对数/指数函数 ======
[docs]
@staticmethod
def log(x: float, base: float = 10) -> float:
"""Calculates logarithm of x with given base."""
if x <= 0:
raise ValueError("x must be positive")
if base <= 0 or base == 1:
raise ValueError("base must be positive and not equal to 1")
return math.log(x, base)
[docs]
@staticmethod
def ln(x: float) -> float:
"""Calculates natural (base-e) logarithm of x."""
if x <= 0:
raise ValueError("x must be positive")
return math.log(x)
[docs]
@staticmethod
def log10(x: float) -> float:
"""Calculates base-10 logarithm of x."""
if x <= 0:
raise ValueError("x must be positive")
return math.log10(x)
[docs]
@staticmethod
def log2(x: float) -> float:
"""Calculates base-2 logarithm of x."""
if x <= 0:
raise ValueError("x must be positive")
return math.log2(x)
[docs]
@staticmethod
def log1p(x: float) -> float:
"""Calculates the natural logarithm of 1+x."""
if x <= -1:
raise ValueError("x must be greater than -1")
return math.log1p(x)
[docs]
@staticmethod
def exp(x: float) -> float:
"""Calculates the exponential of x (e^x)."""
# No range check needed for exp
return math.exp(x)
[docs]
@staticmethod
def expm1(x: float) -> float:
"""Calculates e^x - 1 accurately for small x."""
# No range check needed for expm1
return math.expm1(x)
# ====== Numerical Processing 数值处理 ======
[docs]
@staticmethod
def abs(x: float) -> float:
"""Calculates absolute value of x."""
# No range check needed for abs
return abs(x)
[docs]
@staticmethod
def round(x: float, digits: int = 0) -> float:
"""Rounds x to given number of decimal digits."""
# No range check needed for round
return round(x, digits)
[docs]
@staticmethod
def floor(x: float) -> int:
"""Rounds x down to nearest integer."""
# No range check needed for floor
return math.floor(x)
[docs]
@staticmethod
def ceil(x: float) -> int:
"""Rounds x up to nearest integer."""
# No range check needed for ceil
return math.ceil(x)
[docs]
@staticmethod
def trunc(x: float) -> int:
"""Truncates x by removing the fractional part."""
# No range check needed for trunc
return math.trunc(x)
[docs]
@staticmethod
def copysign(a: float, b: float) -> float:
"""Returns a float with the magnitude of a but the sign of b."""
# No range check needed for copysign
return math.copysign(a, b)
[docs]
@staticmethod
def frexp(x: float):
"""Returns the mantissa and exponent of x as the pair (m, e)."""
# No range check needed for frexp
return math.frexp(x)
[docs]
@staticmethod
def ldexp(x: float, i: int) -> float:
"""Returns x * (2**i) computed exactly."""
# No range check needed for ldexp
return math.ldexp(x, i)
[docs]
@staticmethod
def modf(x: float):
"""Returns the fractional and integer parts of x."""
# No range check needed for modf
return math.modf(x)
[docs]
@staticmethod
def remainder(x: float, y: float) -> float:
"""Returns IEEE 754-style remainder of x/y."""
return math.remainder(x, y)
[docs]
@staticmethod
def nextafter(x: float, y: float) -> float:
"""Returns next floating-point value after x towards y."""
return math.nextafter(x, y)
[docs]
@staticmethod
def ulp(x: float) -> float:
"""Returns the value of the least significant bit of x."""
return math.ulp(x)
[docs]
@staticmethod
def fmod(x: float, y: float) -> float:
"""Returns floating-point remainder of x/y."""
if y == 0:
raise ValueError("Cannot divide by zero")
return math.fmod(x, y)
[docs]
@staticmethod
def isclose(
a: float, b: float, rel_tol: float = 1e-09, abs_tol: float = 0.0
) -> bool:
"""Determines whether two floats are close in value."""
# No range check needed for isclose
return math.isclose(a, b, rel_tol=rel_tol, abs_tol=abs_tol)
# ====== Combinatorics 组合数学 ======
[docs]
@staticmethod
def factorial(n: int) -> int:
"""Calculates factorial of n."""
if n < 0:
raise ValueError("n must be non-negative")
return math.factorial(n)
[docs]
@staticmethod
def gcd(a: int, b: int) -> int:
"""Calculates greatest common divisor of a and b."""
# No range check needed for gcd
return math.gcd(a, b)
[docs]
@staticmethod
def lcm(a: int, b: int) -> int:
"""Calculates least common multiple of a and b."""
# No range check needed for lcm
return abs(a * b) // math.gcd(a, b) if a and b else 0
[docs]
@staticmethod
def comb(n: int, k: int) -> int:
"""Calculates the number of combinations (n choose k)."""
# No range check needed for comb
return math.comb(n, k)
[docs]
@staticmethod
def perm(n: int, k: int) -> int:
"""Calculates the number of permutations of n items taken k at a time."""
# No range check needed for perm
return math.perm(n, k)
# ====== Special Functions 特殊数学函数 ======
[docs]
@staticmethod
def erf(x: float) -> float:
"""Calculates the error function of x."""
# No range check needed for erf
return math.erf(x)
[docs]
@staticmethod
def erfc(x: float) -> float:
"""Calculates the complementary error function of x."""
# No range check needed for erfc
return math.erfc(x)
[docs]
@staticmethod
def gamma(x: float) -> float:
"""Calculates the Gamma function of x."""
# No range check needed for gamma
return math.gamma(x)
[docs]
@staticmethod
def lgamma(x: float) -> float:
"""Calculates the natural logarithm of the absolute value of the Gamma function of x."""
# No range check needed for lgamma
return math.lgamma(x)
# ====== Numerical Validation 数值检查 ======
[docs]
@staticmethod
def isfinite(x: float) -> bool:
"""Checks if x is finite."""
# No range check needed for isfinite
return math.isfinite(x)
[docs]
@staticmethod
def isinf(x: float) -> bool:
"""Checks if x is infinite."""
# No range check needed for isinf
return math.isinf(x)
[docs]
@staticmethod
def isnan(x: float) -> bool:
"""Checks if x is NaN."""
# No range check needed for isnan
return math.isnan(x)
# ====== Statistical functions 统计函数 ======
[docs]
@staticmethod
def average(numbers: List[float]) -> float:
"""Calculates arithmetic mean of numbers."""
if not numbers:
raise ValueError("numbers list cannot be empty")
return sum(numbers) / len(numbers)
[docs]
@staticmethod
def mode(numbers: List[float]) -> List[float]:
"""Finds mode(s) of numbers."""
if not numbers:
raise ValueError("numbers list cannot be empty")
freq: Dict[float, int] = {}
for num in numbers:
freq[num] = freq.get(num, 0) + 1
max_count = max(freq.values())
return [num for num, count in freq.items() if count == max_count]
[docs]
@staticmethod
def standard_deviation(numbers: List[float]) -> float:
"""Calculates population standard deviation of numbers."""
if not numbers:
raise ValueError("numbers list cannot be empty")
mean = Calculator.average(numbers)
variance = sum((x - mean) ** 2 for x in numbers) / len(numbers)
return math.sqrt(variance)
[docs]
@staticmethod
def min(numbers: List[float]) -> float:
"""Finds the minimum value in a list of numbers."""
if not numbers:
raise ValueError("numbers list cannot be empty")
return min(numbers)
[docs]
@staticmethod
def max(numbers: List[float]) -> float:
"""Finds the maximum value in a list of numbers."""
if not numbers:
raise ValueError("numbers list cannot be empty")
return max(numbers)
[docs]
@staticmethod
def sum(numbers: List[float]) -> float:
"""Calculates the sum of a list of numbers."""
# No range check needed for sum
return sum(numbers)
[docs]
@staticmethod
def prod(numbers: List[float]) -> float:
"""Calculates the product of a list of numbers."""
# No range check needed for prod
return math.prod(numbers)
[docs]
@staticmethod
def fsum(numbers: List[float]) -> float:
"""Calculates an accurate floating point sum of numbers."""
# No range check needed for fsum
return math.fsum(numbers)
# ====== Financial calculations 金融计算 ======
[docs]
@staticmethod
def simple_interest(principal: float, rate: float, time: float) -> float:
"""Calculates simple interest.
Args:
principal (float): Initial amount
rate (float): Annual interest rate (decimal)
time (float): Time in years
Returns:
float: Simple interest amount
"""
# No range check needed for simple_interest
return principal * rate * time
[docs]
@staticmethod
def compound_interest(
principal: float, rate: float, time: float, periods: int = 1
) -> float:
"""Calculates compound interest.
Args:
principal (float): Initial amount
rate (float): Annual interest rate (decimal)
time (float): Time in years
periods (int, optional): Compounding periods per year. Defaults to 1.
Returns:
float: Final amount after compounding
"""
# No range check needed for compound_interest
return principal * (1 + rate / periods) ** (periods * time)
# ====== Random number generation 随机数生成 ======
[docs]
@staticmethod
def random() -> float:
"""Generates random float between 0 and 1."""
# No range check needed for random
return random.random()
[docs]
@staticmethod
def randint(a: int, b: int) -> int:
"""Generates random integer between a and b."""
if a > b:
raise ValueError("a must be <= b")
return random.randint(a, b)
# ====== Expression evaluation 表达式求值 ======
[docs]
@staticmethod
def evaluate(expression: str) -> Union[float, int, bool]:
"""Evaluates a mathematical expression using a unified interface.
This method is intended for complex expressions that combine two or more operations.
For simple, single-step operations, please directly use the corresponding static method (e.g., add, subtract).
The evaluate method supports the following operations:
- Constants: pi, e, tau, inf, nan
- Basic arithmetic: add, subtract, multiply, divide, mod
- Power and roots: power, sqrt, cbrt, isqrt
- Distance and norm: dist, hypot
- Trigonometric functions: sin, cos, tan, asin, acos, atan, degrees, radians
- Hyperbolic functions: sinh, cosh, tanh, asinh, acosh, atanh
- Logarithmic and exponential functions: log, ln, log10, log2, log1p, exp, expm1
- Numerical processing: abs, round, floor, ceil, trunc, copysign, frexp, ldexp, modf, remainder, nextafter, ulp, fmod, isclose
- Combinatorics: factorial, gcd, lcm, comb, perm
- Special functions: erf, erfc, gamma, lgamma
- Numerical validation: isfinite, isinf, isnan
- Statistical functions: average, median, mode, standard_deviation, min, max, sum, prod, fsum
- Financial calculations: simple_interest, compound_interest
- Random number generation: random, randint
The expression should be a valid Python expression utilizing the above functions.
For example: "add(2, 3) * power(2, 3) + sqrt(16)".
Args:
expression (str): Mathematical expression to evaluate.
Returns:
Union[float, int, bool]: The result of the evaluated expression.
Raises:
ValueError: If the expression is invalid or its evaluation fails.
"""
# Get all static methods from Calculator class using __dict__,
# excluding 'evaluate' to avoid redundancy.
allowed_functions = {
name: func.__func__
for name, func in Calculator.__dict__.items()
if isinstance(func, staticmethod) and name not in ("evaluate")
}
allowed_functions.update(
{
"pow": Calculator.power,
}
)
# Add basic builtins
try:
return eval(expression, {"__builtins__": None}, allowed_functions)
except Exception as e:
raise ValueError(f"Invalid expression: {e}")