Skip to content

Python's math module

The standard math module of python cannot be interfaced to work transparently with physipy. We propose an drop-in replace module in physipy.math so you get the same functions from the standard module while supporting units.

import math
from math import pi
from physipy import m, rad, Quantity, Dimension
import physipy.math as phymath

If the inputs are regular numbers (like int and float), you'll get the same results as with the standard math module - but with a speed loss due to the unit-handling overhead :

print(math.cos(5))      # call from the standard module
print(phymath.cos(5))   # call from the physipy module
0.28366218546322625
0.28366218546322625

When using the physipy.math module, dimension checks are made to the inputs of the functions where this applies. For example, the trigonomectric functions do not accept units except angles :

# trigonometric functions accept quantities that are angles
print(phymath.cos(pi*rad))   

# but not any other units
try:
    phymath.cos(pi*m)       
except BaseException as e:
    print("Trigonometrics functions only accept quantities that are angles or are unitless : ")
    print(e)
-1.0
Trigonometrics functions only accept quantities that are angles or are unitless : 
Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless).

Some function will return a Quantity if the input is itself a Quantity, with the same unit - like the ceil function :

print(math.ceil(5.3))       # using standard module
print(phymath.ceil(5.3))    # using physipy's math module on a float
print(phymath.ceil(5.3*m))  # using physipy's math module on a Quantity
6
6
6 m

Overall, each function has a precise way to deal with units - wheter it is to check the input or to return unitfull quantities, depending on the underlying mathematical operations of that function.

An in-depth comparison between math and physipy.math

import math
from math import acos, acosh, asin, asinh, atan, atan2, atanh
from math import ceil, copysign, comb, cos, cosh
from math import degrees, dist
from math import erf, erfc, exp, expm1
from math import fabs, factorial, floor, fmod, frexp, fsum
from math import gamma, gcd
from math import hypot
from math import isclose, isfinite, isinf, isnan, isqrt
from math import ldexp, lgamma, log, log10, log1p, log2
from math import modf
from math import perm, pow as math_pow, prod
from math import radians, remainder
from math import sin, sinh, sqrt
from math import tan, tanh, trunc

import physipy
# from math import nextafter, ulp, lcm

a = 5.123 * m
b = -2*m
math_params = {
    "acos"     :(acos     , a       ),
    "acosh"    :(acosh    , a       ),
    "asin"     :(asin     , a       ),
    "asinh"    :(asinh    , a       ),
    "atan"     :(atan     , a       ),
    "atan2"    :(atan2    , (a,b)   ),
    "atanh"    :(atanh    , a       ),
    "ceil"     :(ceil     , a       ),
    "coysign"  :(copysign , (a, b)  ),
    #"comb"     :(comb     , 10, 3),  
    "cos"      :(cos      , a       ),
    "cosh"     :(cosh     , a       ),
    "degrees"  :(degrees  , a       ),
    "dist"     :(dist     , ([1*m, 3*m], [2*m, 5*m])),
    "erf"      :(erf      , a       ),
    "erfc"     :(erfc     , a       ),
    "exp"      :(exp      , a       ),
    "expm1"    :(expm1    , a       ),
    "fabs"     :(fabs     , a       ),
    "floor"    :(floor    , a       ),
    "fmod"     :(fmod     , (a, b)  ),
    "fsum"     :(fsum     , [a, a, a]),
    "gamma"    :(gamma    , a       ),
    "gcd"      :(gcd      , (a, a)  ),
    "hypot"    :(hypot    , a       ),
    "isclose"  :(isclose  , (a, b)  ),
    "isfinite" :(isfinite , a       ),
    "isinf"    :(isinf    , a       ), 
    "isnan"    :(isnan    , a       ), 
    "isqrt"    :(isqrt    , a       ),
    "ldexp"    :(ldexp    , (a, a)  ), 
    "lgamma"   :(lgamma   , a       ),
    "log"      :(log      , a       ),
    "log10"    :(log10    , a       ),
    "log1p"    :(log1p    , a       ),
    "log2"     :(log2     , a       ),
    "modf"     :(modf     , a       ),
    "perm"     :(perm     , a       ),
    "pow"      :(math_pow , (a, 2)  ),
    "prod"     :(prod     , [a, a]  ),
    "radians"  :(radians  , a       ),
    "remainder":(remainder, (a, b)  ),
    "sin"      :(sin      , a       ), 
    "sinh"     :(sinh     , a       ), 
    "sqrt"     :(sqrt     , a       ),
    "tan"      :(tan      , a       ), 
    "tanh"     :(tanh     , a       ),
    "trunc"    :(trunc    , a       ),
}


q_rad = 0.4*rad
q = 2.123*m
q_dimless = Quantity(1, Dimension(None))

physipy_math_params = {
    "acos"     :(physipy.math.acos     , q_dimless       ),
    "acosh"    :(physipy.math.acosh    , q_dimless       ),
    "asin"     :(physipy.math.asin     , q_dimless       ),
    "asinh"    :(physipy.math.asinh    , q_dimless       ),
    "atan"     :(physipy.math.atan     , q_dimless       ),
    "atan2"    :(physipy.math.atan2    , (q,q)   ),
    "atanh"    :(physipy.math.atanh    , q_dimless       ),
    "ceil"     :(physipy.math.ceil     , q       ),
    "coysign"  :(physipy.math.copysign , (q, q)  ),
    #"comb"     :(comb     , 10, 3),  
    "cos"      :(physipy.math.cos      , q       ),
    "cosh"     :(physipy.math.cosh     , q       ),
    "degrees"  :(physipy.math.degrees  , q       ),
    "dist"     :(physipy.math.dist     , ([q, q], [q, q])),
    "erf"      :(physipy.math.erf      , q       ),
    "erfc"     :(physipy.math.erfc     , q       ),
    "exp"      :(physipy.math.exp      , q       ),
    "expm1"    :(physipy.math.expm1    , q       ),
    "fabs"     :(physipy.math.fabs     , q       ),
    "floor"    :(physipy.math.floor    , q       ),
    "fmod"     :(physipy.math.fmod     , (q, q)  ),
    "fsum"     :(physipy.math.fsum     , [q, q, q]),
    "gamma"    :(physipy.math.gamma    , q       ),
    "gcd"      :(physipy.math.gcd      , (q, q)  ),
    "hypot"    :(physipy.math.hypot    ,q       ),
    "isclose"  :(physipy.math.isclose  , (a, b)  ),
    "isfinite" :(physipy.math.isfinite ,q       ),
    "isinf"    :(physipy.math.isinf    ,q       ), 
    "isnan"    :(physipy.math.isnan    ,q       ), 
    "isqrt"    :(physipy.math.isqrt    ,q       ),
    "ldexp"    :(physipy.math.ldexp    , (q,q)  ), 
    "lgamma"   :(physipy.math.lgamma   ,q_dimless       ),
    "log"      :(physipy.math.log      ,q_dimless       ),
    "log10"    :(physipy.math.log10    ,q_dimless       ),
    "log1p"    :(physipy.math.log1p    ,q_dimless       ),
    "log2"     :(physipy.math.log2     ,q_dimless       ),
    "modf"     :(physipy.math.modf     ,q       ),
    "perm"     :(physipy.math.perm     ,q       ),
    "pow"      :(physipy.math.pow , (q, 2)  ),
    "prod"     :(physipy.math.prod     , [q,q]  ),
    "radians"  :(physipy.math.radians  ,q       ),
    "remainder":(physipy.math.remainder, (q, b)  ),
    "sin"      :(physipy.math.sin      ,q       ), 
    "sinh"     :(physipy.math.sinh     ,q       ), 
    "sqrt"     :(physipy.math.sqrt     ,q       ),
    "tan"      :(physipy.math.tan      ,q       ), 
    "tanh"     :(physipy.math.tanh     ,q       ),
    "trunc"    :(physipy.math.trunc    ,q       ),
}
import time
class Timer():
    def __enter__(self):
        self.start = time.time()
        return self
    def __exit__(self, *args):
        self.end = time.time()
        self.secs = self.end - self.start
        self.msecs = self.secs * 1000  # millisecs

def color_green_true_red_false(val):
    """
    Takes a scalar and returns a string with
    the css property `'color: red'` for negative
    strings, black otherwise.
    """
    color = 'green' if val else 'red'
    return 'color: %s' % color

def compute_results_dic(param_dict):
    res = {}

    for name, func_and_args in param_dict.items():
        func, args = func_and_args
        results = {}
        try:
            results["Input"] = ", ".join([str(i) for i in args])
        except:
            results["Input"] = str(args)
        if type(args) is tuple:
            # For math
            try:
                with Timer() as timer:
                    v = func(*args)
                    # v = getattr(phymath, name)(*args)
                results["Passed"] = True
                results["Returned"] = str(v)    
                results["Time"] = timer.msecs
            except Exception as e:
                results["Passed"] = False
                results["Returned"] = str(e)   
                results["Time"] = None
        else:
            try:
                with Timer() as timer:
                    v = func(args)
                    # v = getattr(phymath, name)(args)
                results["Passed"] = True
                results["Returned"] = str(v)  
                results["Time"] = timer.msecs
            except Exception as e:
                results["Passed"] = False
                results["Returned"] = str(e)  
                results["Time"] = None
        res[name] = results
    return res

res_math = compute_results_dic(math_params)
res_phymath = compute_results_dic(physipy_math_params)

import pandas as pd
df_math = pd.DataFrame.from_dict(res_math, orient="index")
df_math = df_math.style.applymap(color_green_true_red_false, subset=pd.IndexSlice[:, ['Passed']])
df_phymath = pd.DataFrame.from_dict(res_phymath, orient="index")
df_phymath = df_phymath.style.applymap(color_green_true_red_false, subset=pd.IndexSlice[:, ['Passed']])
C:\Users\ym\Documents\REPOS\physipy\physipy\quantity\quantity.py:753: UserWarning: The unit of the quantity is stripped for __array_struct__
  warnings.warn(f"The unit of the quantity is stripped for {item}")
df_math
  Input Passed Returned Time
acos 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
acosh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
asin 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
asinh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
atan 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
atan2 5.123 m, -2 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
atanh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
ceil 5.123 m True 6 m 0.000000
coysign 5.123 m, -2 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
cos 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
cosh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
degrees 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
dist [, ], [, ] False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
erf 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
erfc 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
exp 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
expm1 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
fabs 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
floor 5.123 m True 5 m 0.000000
fmod 5.123 m, -2 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
fsum 5.123 m, 5.123 m, 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
gamma 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
gcd 5.123 m, 5.123 m False 'Quantity' object cannot be interpreted as an integer nan
hypot 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isclose 5.123 m, -2 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isfinite 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isinf 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isnan 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isqrt 5.123 m False 'Quantity' object cannot be interpreted as an integer nan
ldexp 5.123 m, 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
lgamma 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
log 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
log10 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
log1p 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
log2 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
modf 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
perm 5.123 m False 'Quantity' object cannot be interpreted as an integer nan
pow 5.123 m, 2 False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
prod 5.123 m, 5.123 m True 26.245129000000002 m**2 0.000000
radians 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
remainder 5.123 m, -2 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
sin 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
sinh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
sqrt 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
tan 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
tanh 5.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
trunc 5.123 m True 5 m 0.000000
df_phymath
  Input Passed Returned Time
acos 1 True 0.0 0.000000
acosh 1 True 0.0 0.000000
asin 1 True 1.5707963267948966 0.000000
asinh 1 True 0.8813735870195429 0.000000
atan 1 True 0.7853981633974483 0.000000
atan2 2.123 m, 2.123 m True 0.7853981633974483 0.000000
atanh 1 False math domain error nan
ceil 2.123 m True 3 m 0.000000
coysign 2.123 m, 2.123 m True 2.123 m 0.000000
cos 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
cosh 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
degrees 2.123 m False nan
dist [, ], [, ] False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
erf 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
erfc 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
exp 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
expm1 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
fabs 2.123 m True 2.123 m 0.000000
floor 2.123 m True 2 m 0.000000
fmod 2.123 m, 2.123 m True 0.0 m 0.000000
fsum 2.123 m, 2.123 m, 2.123 m False setting an array element with a sequence. nan
gamma 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
gcd 2.123 m, 2.123 m False nan
hypot 2.123 m False Dimension error : dimension is L but should be no-dimension (length vs dimensionless). nan
isclose 5.123 m, -2 m False nan
isfinite 2.123 m True True 0.000000
isinf 2.123 m True False 0.000000
isnan 2.123 m True False 0.000000
isqrt 2.123 m False nan
ldexp 2.123 m, 2.123 m False nan
lgamma 1 True 0.0 0.000000
log 1 True 0.0 0.000000
log10 1 True 0.0 0.000000
log1p 1 True 0.6931471805599453 0.000000
log2 1 True 0.0 0.000000
modf 2.123 m False nan
perm 2.123 m False nan
pow 2.123 m, 2 False nan
prod 2.123 m, 2.123 m True 4.507129000000001 m**2 0.000000
radians 2.123 m False nan
remainder 2.123 m, -2 m True 0.12300000000000022 m 0.000000
sin 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
sinh 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
sqrt 2.123 m True 1.4570518178843195 m**0.5 0.000000
tan 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
tanh 2.123 m False Dimension error : dimensions of operands are L and no-dimension, and are differents (length vs dimensionless). nan
trunc 2.123 m False type numpy.ndarray doesn't define __trunc__ method nan