"""
@file mathlib.py
@brief Shared mathematical library for the calculator and profiling program.
@details
Provides basic arithmetic operations and helper mathematical functions
used by both the calculator application and the standard deviation program.
@author Jan Kostečka
@date 2026-04-18
"""

#!/usr/bin/env python3
import math


def add(a: float, b: float) -> float:
    """@brief Return the sum of two numbers.

    @param a First operand.
    @param b Second operand.
    @return Sum of a and b.
    """
    return a + b


def subtract(a: float, b: float) -> float:
    """@brief Return the difference of two numbers.

    @param a First operand.
    @param b Second operand.
    @return Difference a - b.
    """
    return a - b


def multiply(a: float, b: float) -> float:
    """@brief Return the product of two numbers.

    @param a First operand.
    @param b Second operand.
    @return Product of a and b.
    """
    return a * b


def divide(a: float, b: float) -> float:
    """@brief Return the quotient of two numbers.

    @param a Dividend.
    @param b Divisor.
    @return Quotient a / b, or NaN when dividing by zero.
    """
    if b == 0:
        return math.nan
    return a / b


def power(a: float, b: float) -> float:
    """@brief Raise a number to a given power.

    @param a Base value.
    @param b Exponent.
    @return Value of a raised to the power b.
    """
    return a ** b


def root(value: float, degree: float) -> float:
    """@brief Compute the root of a number.

    @param value Value whose root is computed.
    @param degree Degree of the root.
    @return The root of the given value, or NaN for invalid input.
    """
    if degree == 0:
        return math.nan
    if value < 0:
        return math.nan
    return value ** (1.0 / degree)


def sqrt(value: float) -> float:
    """@brief Compute the square root of a number.

    @param value Input value.
    @return Square root of the input value.
    """
    return root(value, 2.0)


def modulo(a: float, b: float) -> float:
    """@brief Compute the remainder after division.

    @param a Dividend.
    @param b Divisor.
    @return Remainder a % b, or NaN when dividing by zero.
    """
    if b == 0:
        return math.nan
    return a % b


def pi() -> float:
    """@brief Return the value of the mathematical constant pi.

    @return Value of pi.
    """
    return math.pi


def factorial(n: float) -> float:
    """@brief Compute the factorial of a non-negative integer.

    @param n Input value (should be a non-negative integer).
    @return Factorial of n, or NaN for invalid input.
    """
    try:
        # Convert to integer
        n_int = int(n)
        # Check if n is negative
        if n_int < 0:
            return math.nan
        # Large numbers will automatically be converted to inf to save resources
        if n_int > 9999:
            return math.inf
        # Calculate factorial
        return float(math.factorial(n_int))
    except ValueError:
        return math.nan
    except OverflowError:
        return math.inf
