"""
This file contains the default math functions and constant mathematical values
that are used as base for the entire package.
All the mathematical functions that are not implemented, like `sin` and `cos`
are the same from the standard `math` python's package.
The standard rational number is a instance from `fractions` standard package.
Other libraries offer other options to handle numerical numbers.
To do such, you need to overwrite these base functions and hence the
package will use your numerical type.
Example of use are:
* `numpy` offers `numpy.float64` instead of float
* `mpmath` offers the `mpmath.mpf` of arbitrary precision of float
* `sympy` offers `sympy.core.numbers.Rational` instead of `fractions.Fraction`
"""
from __future__ import annotations
import math
from fractions import Fraction
from numbers import Integral, Rational, Real
from typing import Any, Callable
from ..tools import Is, To
def is_finite(number: Real) -> bool:
"""
Check if a number is finite.
Parameters
----------
number : Real
The number to check for being finite
Returns
-------
bool
True if the number is finite, False otherwise
Examples
--------
>>> Is.finite(float("inf"))
False
>>> Is.finite(0)
True
"""
return Is.real(number) and math.isfinite(number)
def is_infinity(number: Real) -> bool:
"""
Check if a number is negative or positive infinity.
Parameters
----------
number : Real
The number to check for being infinity
Returns
-------
bool
True if the number is infinity, False otherwise
Examples
--------
>>> Is.infinity(-float("inf"))
True
>>> Is.infinity(float("inf"))
True
>>> Is.infinity(0)
False
"""
return Is.real(number) and math.isinf(number)
def is_integer(number: Real) -> bool:
"""
Check if a number is integer.
Parameters
----------
number : Real
The number to check for being an integer
Returns
-------
bool
True if the number is integer, False otherwise
Examples
--------
>>> Is.integer(1)
True
>>> Is.integer(1.2)
False
"""
return Is.instance(number, Integral)
def is_rational(number: Real) -> bool:
"""
Check if a number is integer or rational.
Parameters
----------
number : Real
The number to check for rationality
Returns
-------
bool
True if the number is rational, False otherwise
Examples
--------
>>> Is.rational(1)
True
>>> Is.rational(Fraction(1, 2))
True
>>> Is.rational(0.5)
"""
return Is.real(number) and Is.instance(number, Rational)
def is_real(value: object) -> bool:
"""
Check if a number is a real number.
Parameters
----------
value : object
The object to check for being a number
Returns
-------
bool
True if the number is a number, False otherwise
Examples
--------
>>> Is.real(float("inf"))
True
>>> Is.real(0)
True
>>> Is.real("asd")
False
"""
return Is.instance(value, Real)
def to_real(number: Any) -> Real:
"""
Converts the number to a real number.
Parameters
----------
number : Any
Number to be converted to a real number
Returns
-------
Real
The converted real number
Examples
--------
>>> To.real(-1)
-1
>>> To.real(0)
0
>>> To.real(1)
1
>>> To.real(1.5)
1.5
>>> To.real(float("inf"))
inf
>>> To.real("inf")
inf
"""
if Is.instance(number, Real):
return number
return To.float(number)
def to_finite(number: Any) -> Real:
"""
Converts the number to an finite number.
Parameters
----------
number : Any
Number to be converted to an integer
Returns
-------
Real
The converted number in integer
Raises
------
ValueError
If the number is not finite
Examples
--------
>>> To.finite(-1)
-1
>>> To.finite(0)
0
>>> To.finite(1)
1
>>> To.finite(1.5)
1.5
"""
number = To.real(number)
if not Is.finite(number):
raise ValueError(f"{number} is not finite")
return number
def to_rational(numerator: Rational, denominator: Rational = 1) -> Rational:
"""
Divide two rational numbers and return the result as a fraction.
If any input is not integer/rational, performs standard division.
Parameters
----------
numerator : int or rational or float
The numerator number
denominator : int or rational or float
The divisor number
Returns
-------
Rational
A instance if inputs are integers/rational
Raises
------
ZeroDivisionError
If denominator is zero
TypeError
If inputs are not numeric types
Notes
-----
This function preserves exact rational representation when inputs are
integers or rational numbers. For example:
Examples
--------
>>> To.rational(1, 2)
Fraction(1, 2)
>>> To.rational(12, 9)
Fraction(4, 3)
>>> To.rational(22, 7)
Fraction(22, 7)
"""
numerator = To.real(numerator)
denominator = To.real(denominator)
return Fraction(numerator, denominator)
def to_integer(number: Any) -> Integral:
"""
Converts the number to an integer.
Parameters
----------
number : Real
Number to be converted to an integer
Returns
-------
int
The converted number in integer
Examples
--------
>>> To.integer(-1)
-1
>>> To.integer(0)
0
>>> To.integer(1)
1
"""
if Is.instance(number, Integral):
return number
return int(number)
[docs]
class Math:
"""
Contains static methods for mathematical functions
"""
tau: Real = math.tau
radsin: Callable[[Real], Real] = math.sin
radcos: Callable[[Real], Real] = math.cos
sinh: Callable[[Real], Real] = math.sinh
cosh: Callable[[Real], Real] = math.cosh
NEGINF = -math.inf
POSINF = math.inf
binom: Callable[[int, int], int] = math.comb
factorial: Callable[[int], int] = math.factorial
sqrt: Callable[[Real], Real] = math.sqrt
[docs]
@staticmethod
def tursin(angle: Real):
"""
Compute the sine of an angle in unitary form (turns).
This function is equivalent to `math.sin(2*math.pi*angle)`
Reference:
* https://en.wikipedia.org/wiki/Turn_(angle)
Parameters
----------
angle : Real
Angle in turns measure
Returns
-------
float
Sine of the unitary angle
Examples
--------
>>> tursin(0) # sine of 0 degrees
0
>>> tursin(0.25) # sine of 90 degrees
1
>>> tursin(0.5) # sine of 180 degrees
0
>>> tursin(0.75) # sine of 270 degrees
-1
>>> tursin(1) # sine of 360 degrees
0
"""
return Math.radsin(Math.tau * angle)
[docs]
@staticmethod
def turcos(angle: Real):
"""
Compute the cossinus of an angle in unitary form (turns).
This function is equivalent to `math.cos(2*math.pi*angle)`
Reference:
* https://en.wikipedia.org/wiki/Turn_(angle)
Parameters
----------
angle : Real
Angle in turns measure
Returns
-------
float
Cossinus of the unitary angle
Examples
--------
>>> turcos(0) # cossinus of 0 degrees
1
>>> turcos(0.25) # cossinus of 90 degrees
0
>>> turcos(0.5) # cossinus of 180 degrees
-1
>>> turcos(0.75) # cossinus of 270 degrees
0
>>> turcos(1) # cossinus of 360 degrees
1
"""
return Math.radcos(Math.tau * angle)
[docs]
@staticmethod
def fmod(numer: Real, denom: Real) -> Real:
"""
Returns the floating-point remainder of division x1/x2.
Parameters
----------
numer : float
Dividend
denom : float
Divisor
Returns
-------
float
The remainder of x divided by y, with the same sign as x.
Examples
--------
>>> fmod(5.0, 2.0)
1.0
>>> fmod(-5.0, 2.0)
-1.0
>>> fmod(5.0, -2.0)
1.0
"""
return To.real(math.fmod(numer, denom))
[docs]
@staticmethod
def hypot(xcoord: Real, ycoord: Real) -> Real:
"""
Calculate Euclidean distance from origin point (0,0).
Parameters
----------
xcoord : float
The x-coordinate of the point
ycoord : float
The y-coordinate of the point
Returns
-------
float
The Euclidean distance from the origin point (0,0)
Examples
--------
>>> calculate_distance_from_origin(3, 4)
5.0
>>> calculate_distance_from_origin(0, 0)
0.0
"""
return To.real(math.hypot(xcoord, ycoord))
[docs]
@staticmethod
def atan2(ycoord: Real, xcoord: Real) -> Real:
"""
Compute the arc tangent of y/x choosing the quadrant correctly.
Parameters
----------
ycoord : Real
The y-coordinate of the point
xcoord : Real
The x-coordinate of the point
Returns
-------
float
Array of angles in radians in the range [-pi, pi)
Examples
--------
>>> arctan2(1, 1) # 45 degrees = π/4 radians
0.7853981633974483
>>> arctan2(-1, 1) # -45 degrees = -π/4 radians
-0.7853981633974483
>>> arctan2(1, -1) # 135 degrees = 3π/4 radians
2.3561944901923448
"""
return To.finite(math.atan2(ycoord, xcoord))
[docs]
@staticmethod
def degrees(angle: Real) -> Real:
"""
Convert an angle from radians to degrees.
This function performs the angular conversion using the mathematical
relationship that pi radians equals 180 degrees.
The conversion factor is calculated as 180/pi, ensuring precise
transformation between the two angular measurement systems.
Parameters
----------
angle : Real
The angle in radians to convert
Returns
-------
Real
The equivalent angle in degrees
Examples
--------
>>> degrees(0)
0
>>> degrees(pi / 2)
90
>>> degrees(pi)
180
Notes
-----
This function uses the math module's degrees() function internally,
which handles edge cases and provides optimal numerical precision
for the conversion.
Raises:
TypeError: If the input is not a numeric type
"""
return To.finite(math.degrees(angle))
Is.real = is_real
Is.finite = is_finite
Is.infinity = is_infinity
Is.integer = is_integer
Is.rational = is_rational
To.real = to_real
To.finite = to_finite
To.rational = to_rational
To.integer = to_integer