math — Funciones Matemáticas

Propósito:Proporciona funciones para operaciones matemáticas especializadas.

El módulo math implementa muchas de las funciones IEEE que normalmente se encontraría en las bibliotecas nativas de la plataforma C para operaciones complejas matemáticas usando valores de coma flotante, incluyendo logaritmos y operaciones trigonométricas.

Constantes especiales

Muchas operaciones matemáticas dependen de constantes especiales. math incluye valores para n (pi), e, nan (no un número) e infinito.

math_constants.py
import math

print('  π: {:.30f}'.format(math.pi))
print('  e: {:.30f}'.format(math.e))
print('nan: {:.30f}'.format(math.nan))
print('inf: {:.30f}'.format(math.inf))

Tanto π como e están limitados en precisión solo por la biblioteca de coma flotante de la plataforma.

$ python3 math_constants.py

  π: 3.141592653589793115997963468544
  e: 2.718281828459045090795598298428
nan: nan
inf: inf

Prueba de valores excepcionales

Los cálculos de coma flotante pueden dar lugar en dos tipos de valores excepcionales. El primero de ellos, inf (infinito), aparece cuando el double usado para mantener un valor de coma flotante se desborda de un valor con un gran valor absoluto.

math_isinf.py
import math

print('{:^3} {:6} {:6} {:6}'.format(
    'e', 'x', 'x**2', 'isinf'))
print('{:-^3} {:-^6} {:-^6} {:-^6}'.format(
    '', '', '', ''))

for e in range(0, 201, 20):
    x = 10.0 ** e
    y = x * x
    print('{:3d} {:<6g} {:<6g} {!s:6}'.format(
        e, x, y, math.isinf(y),
    ))

Cuando el exponente en este ejemplo crezca lo suficiente, el cuadrado de x ya no cabe dentro de un double, y el valor se registra como infinito.

$ python3 math_isinf.py

 e  x      x**2   isinf
--- ------ ------ ------
  0 1      1      False
 20 1e+20  1e+40  False
 40 1e+40  1e+80  False
 60 1e+60  1e+120 False
 80 1e+80  1e+160 False
100 1e+100 1e+200 False
120 1e+120 1e+240 False
140 1e+140 1e+280 False
160 1e+160 inf    True
180 1e+180 inf    True
200 1e+200 inf    True

Sin embargo, no todos los desbordamientos de coma flotante dan como resultado valores inf. Calcular un exponente con valores de coma flotante, en particular, levanta OverflowError en lugar de preservar el resultado inf.

math_overflow.py
x = 10.0 ** 200

print('x    =', x)
print('x*x  =', x * x)
print('x**2 =', end=' ')
try:
    print(x ** 2)
except OverflowError as err:
    print(err)

Esta discrepancia es causada por una diferencia de implementación en la biblioteca utilizada por C Python.

$ python3 math_overflow.py

x    = 1e+200
x*x  = inf
x**2 = (34, 'Result too large')

Las operaciones de división que usan valores infinitos no están definidas. El resultado de dividir un número por infinito es nan (no es un número).

math_isnan.py
import math

x = (10.0 ** 200) * (10.0 ** 200)
y = x / x

print('x =', x)
print('isnan(x) =', math.isnan(x))
print('y = x / x =', x / x)
print('y == nan =', y == float('nan'))
print('isnan(y) =', math.isnan(y))

nan no se compara como igual a ningún valor, incluso a sí mismo, por lo que para comprobar si es nan usa isnan().

$ python3 math_isnan.py

x = inf
isnan(x) = False
y = x / x = nan
y == nan = False
isnan(y) = True

Usa isfinite() para verificar si hay números regulares o cualquiera de los valores especiales inf o nan.

math_isfinite.py
import math

for f in [0.0, 1.0, math.pi, math.e, math.inf, math.nan]:
    print('{:5.2f} {!s}'.format(f, math.isfinite(f)))

isfinite() devuelve falso para cualquiera de los casos excepcionales, y cierto de lo contrario.

$ python3 math_isfinite.py

 0.00 True
 1.00 True
 3.14 True
 2.72 True
  inf False
  nan False

Comparando

Las comparaciones para los valores de coma flotante pueden ser propensas a errores, con cada paso de la computación que potencialmente introduce errores debido a la representación numérica. La función isclose() usa un algoritmo estable para minimizar estos errores y proporciona una manera de para comparaciones relativas así como comparaciones absolutas. La fórmula utilizada es equivalente a

abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol)

Por defecto, isclose() usa una comparación relativa con la tolerancia establecida en 1e-09, lo que significa que la diferencia entre los valores deben ser menor o igual a 1e-09 multiplicado por el mayor valor absoluto entre a y b. Pasando un argumento de palabra clave rel_tol a isclose() cambia la tolerancia. En este ejemplo, los valores deben estar dentro del 10% de cada uno.

math_isclose.py
import math

INPUTS = [
    (1000, 900, 0.1),
    (100, 90, 0.1),
    (10, 9, 0.1),
    (1, 0.9, 0.1),
    (0.1, 0.09, 0.1),
]

print('{:^8} {:^8} {:^8} {:^8} {:^8} {:^8}'.format(
    'a', 'b', 'rel_tol', 'abs(a-b)', 'tolerance', 'close')
)
print('{:-^8} {:-^8} {:-^8} {:-^8} {:-^8} {:-^8}'.format(
    '-', '-', '-', '-', '-', '-'),
)

fmt = '{:8.2f} {:8.2f} {:8.2f} {:8.2f} {:8.2f} {!s:>8}'

for a, b, rel_tol in INPUTS:
    close = math.isclose(a, b, rel_tol=rel_tol)
    tolerance = rel_tol * max(abs(a), abs(b))
    abs_diff = abs(a - b)
    print(fmt.format(a, b, rel_tol, abs_diff, tolerance, close))

La comparación entre 0.1 y 0.09 falla debido al error representando 0.1.

$ python3 math_isclose.py

   a        b     rel_tol  abs(a-b) tolerance  close
-------- -------- -------- -------- -------- --------
 1000.00   900.00     0.10   100.00   100.00     True
  100.00    90.00     0.10    10.00    10.00     True
   10.00     9.00     0.10     1.00     1.00     True
    1.00     0.90     0.10     0.10     0.10     True
    0.10     0.09     0.10     0.01     0.01    False

Para usar una tolerancia fija o «absoluta», pasa abs_tol en lugar de rel_tol.

math_isclose_abs_tol.py
import math

INPUTS = [
    (1.0, 1.0 + 1e-07, 1e-08),
    (1.0, 1.0 + 1e-08, 1e-08),
    (1.0, 1.0 + 1e-09, 1e-08),
]

print('{:^8} {:^11} {:^8} {:^10} {:^8}'.format(
    'a', 'b', 'abs_tol', 'abs(a-b)', 'close')
)
print('{:-^8} {:-^11} {:-^8} {:-^10} {:-^8}'.format(
    '-', '-', '-', '-', '-'),
)

for a, b, abs_tol in INPUTS:
    close = math.isclose(a, b, abs_tol=abs_tol)
    abs_diff = abs(a - b)
    print('{:8.2f} {:11} {:8} {:0.9f} {!s:>8}'.format(
        a, b, abs_tol, abs_diff, close))

Para una tolerancia absoluta, la diferencia entre los valores de entrada debe ser menor que la tolerancia definida.

$ python3 math_isclose_abs_tol.py

   a          b      abs_tol   abs(a-b)   close
-------- ----------- -------- ---------- --------
    1.00   1.0000001    1e-08 0.000000100    False
    1.00  1.00000001    1e-08 0.000000010     True
    1.00 1.000000001    1e-08 0.000000001     True

nan y inf son casos especiales.

math_isclose_inf.py
import math

print('nan, nan:', math.isclose(math.nan, math.nan))
print('nan, 1.0:', math.isclose(math.nan, 1.0))
print('inf, inf:', math.isclose(math.inf, math.inf))
print('inf, 1.0:', math.isclose(math.inf, 1.0))

nan nunca está cerca de otro valor, incluido él mismo. inf es solo cerca de sí mismo.

$ python3 math_isclose_inf.py

nan, nan: False
nan, 1.0: False
inf, inf: True
inf, 1.0: False

Convirtiendo valores de coma flotante en enteros

El módulo math incluye tres funciones para la conversión de valores de coma flotante a números enteros. Cada toma un enfoque diferente, y es útil en diferentes circunstancias.

La más simple es trunc(), que trunca los dígitos después de la coma, dejando solo los dígitos significativos que componen el toda la parte de valor del número. floor() convierte su entrada al mayor entero precedente, y ceil() (techo) produce el número entero más grande siguiendo secuencialmente después del valor de entrada.

math_integers.py
import math

HEADINGS = ('i', 'int', 'trunk', 'floor', 'ceil')
print('{:^5} {:^5} {:^5} {:^5} {:^5}'.format(*HEADINGS))
print('{:-^5} {:-^5} {:-^5} {:-^5} {:-^5}'.format(
    '', '', '', '', '',
))

fmt = '{:5.1f} {:5.1f} {:5.1f} {:5.1f} {:5.1f}'

TEST_VALUES = [
    -1.5,
    -0.8,
    -0.5,
    -0.2,
    0,
    0.2,
    0.5,
    0.8,
    1,
]

for i in TEST_VALUES:
    print(fmt.format(
        i,
        int(i),
        math.trunc(i),
        math.floor(i),
        math.ceil(i),
    ))

trunc() es equivalente a convertir a int directamente.

$ python3 math_integers.py

  i    int  trunk floor ceil
----- ----- ----- ----- -----
 -1.5  -1.0  -1.0  -2.0  -1.0
 -0.8   0.0   0.0  -1.0   0.0
 -0.5   0.0   0.0  -1.0   0.0
 -0.2   0.0   0.0  -1.0   0.0
  0.0   0.0   0.0   0.0   0.0
  0.2   0.0   0.0   0.0   1.0
  0.5   0.0   0.0   0.0   1.0
  0.8   0.0   0.0   0.0   1.0
  1.0   1.0   1.0   1.0   1.0

Representaciones alternativas de valores de coma flotante

modf() toma un solo número de coma flotante y devuelve una tupla que contiene las partes fraccionarias y de números enteros del valor de entrada.

math_modf.py
import math

for i in range(6):
    print('{}/2 = {}'.format(i, math.modf(i / 2.0)))

Ambos números en el valor de retorno son de coma flotante.

$ python3 math_modf.py

0/2 = (0.0, 0.0)
1/2 = (0.5, 0.0)
2/2 = (0.0, 1.0)
3/2 = (0.5, 1.0)
4/2 = (0.0, 2.0)
5/2 = (0.5, 2.0)

frexp() devuelve la mantisa y el exponente de un número de coma flotante, y se puede usar para crear una representación más portátil de el valor.

math_frexp.py
import math

print('{:^7} {:^7} {:^7}'.format('x', 'm', 'e'))
print('{:-^7} {:-^7} {:-^7}'.format('', '', ''))

for x in [0.1, 0.5, 4.0]:
    m, e = math.frexp(x)
    print('{:7.2f} {:7.2f} {:7d}'.format(x, m, e))

frexp() usa la fórmula x = m * 2**e, y devuelve los valores m y e.

$ python3 math_frexp.py

   x       m       e
------- ------- -------
   0.10    0.80      -3
   0.50    0.50       0
   4.00    0.50       3

ldexp() es el inverso de frexp().

math_ldexp.py
import math

print('{:^7} {:^7} {:^7}'.format('m', 'e', 'x'))
print('{:-^7} {:-^7} {:-^7}'.format('', '', ''))

INPUTS = [
    (0.8, -3),
    (0.5, 0),
    (0.5, 3),
]

for m, e in INPUTS:
    x = math.ldexp(m, e)
    print('{:7.2f} {:7d} {:7.2f}'.format(m, e, x))

Usando la misma fórmula que frexp(), ldexp() toma los valores de mantisa y exponente como argumentos y devuelve un número de coma flotante.

$ python3 math_ldexp.py

   m       e       x
------- ------- -------
   0.80      -3    0.10
   0.50       0    0.50
   0.50       3    4.00

Signos positivos y negativos

El valor absoluto de un número es su valor sin signo. Utiliza fabs() para calcular el valor absoluto de un número de coma flotante.

math_fabs.py
import math

print(math.fabs(-1.1))
print(math.fabs(-0.0))
print(math.fabs(0.0))
print(math.fabs(1.1))

En términos prácticos, el valor absoluto de un float es representado como un valor positivo.

$ python3 math_fabs.py

1.1
0.0
0.0
1.1

Para determinar el signo de un valor, ya sea para dar un conjunto de valores, el mismo signo o para comparar dos valores, usa copysign() para configurar el signo de un valor bueno conocido.

math_copysign.py
import math

HEADINGS = ('f', 's', '< 0', '> 0', '= 0')
print('{:^5} {:^5} {:^5} {:^5} {:^5}'.format(*HEADINGS))
print('{:-^5} {:-^5} {:-^5} {:-^5} {:-^5}'.format(
    '', '', '', '', '',
))

VALUES = [
    -1.0,
    0.0,
    1.0,
    float('-inf'),
    float('inf'),
    float('-nan'),
    float('nan'),
]

for f in VALUES:
    s = int(math.copysign(1, f))
    print('{:5.1f} {:5d} {!s:5} {!s:5} {!s:5}'.format(
        f, s, f < 0, f > 0, f == 0,
    ))

Una función adicional como copysign() se necesita porque comparar nan y -nan directamente con otros valores no funciona.

$ python3 math_copysign.py

  f     s    < 0   > 0   = 0
----- ----- ----- ----- -----
 -1.0    -1 True  False False
  0.0     1 False False True
  1.0     1 False True  False
 -inf    -1 True  False False
  inf     1 False True  False
  nan    -1 False False False
  nan     1 False False False

Cálculos de uso común

La representación de valores precisos en la memoria de coma flotante binaria es desafiante. Algunos valores no se pueden representar exactamente, y a menudo que se manipula un valor a través de cálculos repetidos, es más probable que se introduzca un error de representación. math incluye una función para calcular la suma de una serie de números de coma flotante usando un algoritmo eficiente que minimiza dichos errores.

math_fsum.py
import math

values = [0.1] * 10

print('Input values:', values)

print('sum()       : {:.20f}'.format(sum(values)))

s = 0.0
for i in values:
    s += i
print('for-loop    : {:.20f}'.format(s))

print('math.fsum() : {:.20f}'.format(math.fsum(values)))

Dada una secuencia de diez valores, cada uno igual a 0.1, el valor esperado para la suma de la secuencia es 1.0. Como 0.1 no puede ser representado exactamente como un valor de coma flotante, sin embargo, los errores son introducidos en la suma a menos que se calcule con fsum().

$ python3 math_fsum.py

Input values: [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
sum()       : 0.99999999999999988898
for-loop    : 0.99999999999999988898
math.fsum() : 1.00000000000000000000

factorial() se usa comúnmente para calcular el número de permutaciones y combinaciones de una serie de objetos. El factorial de un entero positivo n, expresado n!, se define recursivamente como (n-1)!*n y se detiene con 0! == 1.

math_factorial.py
import math

for i in [0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.1]:
    try:
        print('{:2.0f} {:6.0f}'.format(i, math.factorial(i)))
    except ValueError as err:
        print('Error computing factorial({}): {}'.format(i, err))

factorial() solo funciona con números enteros, pero acepta argumentos float siempre que puedan convertirse a enteros sin perder valor.

$ python3 math_factorial.py

 0      1
 1      1
 2      2
 3      6
 4     24
 5    120
Error computing factorial(6.1): factorial() only accepts integral
 values

gamma() es como factorial(), excepto que funciona con números reales y el valor se desplaza hacia abajo en uno (gamma es igual a (n - 1)!).

math_gamma.py
import math

for i in [0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6]:
    try:
        print('{:2.1f} {:6.2f}'.format(i, math.gamma(i)))
    except ValueError as err:
        print('Error computing gamma({}): {}'.format(i, err))

Como cero causa que el valor de inicio sea negativo, no está permitido.

$ python3 math_gamma.py

Error computing gamma(0): math domain error
1.1   0.95
2.2   1.10
3.3   2.68
4.4  10.14
5.5  52.34
6.6 344.70

lgamma() devuelve el logaritmo natural del valor absoluto de gamma para el valor de entrada.

math_lgamma.py
import math

for i in [0, 1.1, 2.2, 3.3, 4.4, 5.5, 6.6]:
    try:
        print('{:2.1f} {:.20f} {:.20f}'.format(
            i,
            math.lgamma(i),
            math.log(math.gamma(i)),
        ))
    except ValueError as err:
        print('Error computing lgamma({}): {}'.format(i, err))

El uso de lgamma() conserva más precisión que el cálculo del logaritmo por separado usando los resultados de gamma().

$ python3 math_lgamma.py

Error computing lgamma(0): math domain error
1.1 -0.04987244125984036103 -0.04987244125983997245
2.2 0.09694746679063825923 0.09694746679063866168
3.3 0.98709857789473387513 0.98709857789473409717
4.4 2.31610349142485727469 2.31610349142485727469
5.5 3.95781396761871651080 3.95781396761871606671
6.6 5.84268005527463252236 5.84268005527463252236

El operador de módulo (%) calcula el resto de una expresión de división (es decir, 5 % 2 = 1). El operador integrado en el lenguaje funciona bien con enteros, pero, como con tantas otras operaciones de coma flotante, cálculos intermedios causan problemas de representación que resultan en una pérdida de datos. fmod() proporciona un implementación más precisa para valores de coma flotante.

math_fmod.py
import math

print('{:^4} {:^4} {:^5} {:^5}'.format(
    'x', 'y', '%', 'fmod'))
print('{:-^4} {:-^4} {:-^5} {:-^5}'.format(
    '-', '-', '-', '-'))

INPUTS = [
    (5, 2),
    (5, -2),
    (-5, 2),
]

for x, y in INPUTS:
    print('{:4.1f} {:4.1f} {:5.2f} {:5.2f}'.format(
        x,
        y,
        x % y,
        math.fmod(x, y),
    ))

Una fuente de confusión potencialmente más frecuente es el hecho de que el algoritmo utilizado por fmod() para calcular el módulo también es diferente de el usado por %, por lo que el signo del resultado es diferente.

$ python3 math_fmod.py

 x    y     %   fmod
---- ---- ----- -----
 5.0  2.0  1.00  1.00
 5.0 -2.0 -1.00  1.00
-5.0  2.0  1.00 -1.00

Usa gcd() para encontrar el entero más grande que puede dividirse de manera uniforme en dos enteros, el mayor divisor común.

math_gcd.py
import math

print(math.gcd(10, 8))
print(math.gcd(10, 0))
print(math.gcd(50, 225))
print(math.gcd(11, 9))
print(math.gcd(0, 0))

Si ambos valores son 0, el resultado es 0.

$ python3 math_gcd.py

2
10
25
1
0

Exponentes y Logaritmos

Las curvas de crecimiento exponencial aparecen en economía, física y otras ciencias. Python tiene un operador de exponenciación incorporado («**»), pero pow() puede ser útil cuando se necesita una función invocable como argumento a otra función.

math_pow.py
import math

INPUTS = [
    # Typical uses
    (2, 3),
    (2.1, 3.2),

    # Always 1
    (1.0, 5),
    (2.0, 0),

    # Not-a-number
    (2, float('nan')),

    # Roots
    (9.0, 0.5),
    (27.0, 1.0 / 3),
]

for x, y in INPUTS:
    print('{:5.1f} ** {:5.3f} = {:6.3f}'.format(
        x, y, math.pow(x, y)))

Elevar 1 a cualquier potencia siempre de vuelve 1.0, al igual que elevar cualquier valor a una potencia de 0.0. La mayoría de las operaciones en el valor no número nan devuelven nan. Si el exponente es menor que 1, pow() calcula una raíz.

$ python3 math_pow.py

  2.0 ** 3.000 =  8.000
  2.1 ** 3.200 = 10.742
  1.0 ** 5.000 =  1.000
  2.0 ** 0.000 =  1.000
  2.0 **   nan =    nan
  9.0 ** 0.500 =  3.000
 27.0 ** 0.333 =  3.000

Como las raíces cuadradas (exponente de 1/2) se usan con tanta frecuencia, hay una función separada para computarlos.

math_sqrt.py
import math

print(math.sqrt(9.0))
print(math.sqrt(3))
try:
    print(math.sqrt(-1))
except ValueError as err:
    print('Cannot compute sqrt(-1):', err)

Calcular las raíces cuadradas de números negativos requiere números complejos, que no son manejados por math. Cualquier intento de calcular una raíz cuadrada de un valor negativo da como resultado un ValueError.

$ python3 math_sqrt.py

3.0
1.7320508075688772
Cannot compute sqrt(-1): math domain error

La función de logaritmo encuentra y donde x = b ** y. Por defecto, log() calcula el logaritmo natural (la base es e). Si se proporciona un segundo argumento, ese valor se usa como la base.

math_log.py
import math

print(math.log(8))
print(math.log(8, 2))
print(math.log(0.5, 2))

Los logaritmos donde x es menor que uno producen resultados negativos.

$ python3 math_log.py

2.0794415416798357
3.0
-1.0

Hay tres variantes de log(). Dada una representación de coma flotante y errores de redondeo, el valor calculado producido por log(x, b) tiene una precisión limitada, especialmente para algunas bases. log10() calcula log(x, 10), usando un algoritmo más preciso que log().

math_log10.py
import math

print('{:2} {:^12} {:^10} {:^20} {:8}'.format(
    'i', 'x', 'accurate', 'inaccurate', 'mismatch',
))
print('{:-^2} {:-^12} {:-^10} {:-^20} {:-^8}'.format(
    '', '', '', '', '',
))

for i in range(0, 10):
    x = math.pow(10, i)
    accurate = math.log10(x)
    inaccurate = math.log(x, 10)
    match = '' if int(inaccurate) == i else '*'
    print('{:2d} {:12.1f} {:10.8f} {:20.18f} {:^5}'.format(
        i, x, accurate, inaccurate, match,
    ))

Las líneas en la salida con el * final resaltan los valores inexactos.

$ python3 math_log10.py

i       x        accurate       inaccurate      mismatch
-- ------------ ---------- -------------------- --------
 0          1.0 0.00000000 0.000000000000000000
 1         10.0 1.00000000 1.000000000000000000
 2        100.0 2.00000000 2.000000000000000000
 3       1000.0 3.00000000 2.999999999999999556   *
 4      10000.0 4.00000000 4.000000000000000000
 5     100000.0 5.00000000 5.000000000000000000
 6    1000000.0 6.00000000 5.999999999999999112   *
 7   10000000.0 7.00000000 7.000000000000000000
 8  100000000.0 8.00000000 8.000000000000000000
 9 1000000000.0 9.00000000 8.999999999999998224   *

Similar a log10(), log2() calcula el equivalente a math.log(x, 2).

math_log2.py
import math

print('{:>2} {:^5} {:^5}'.format(
    'i', 'x', 'log2',
))
print('{:-^2} {:-^5} {:-^5}'.format(
    '', '', '',
))

for i in range(0, 10):
    x = math.pow(2, i)
    result = math.log2(x)
    print('{:2d} {:5.1f} {:5.1f}'.format(
        i, x, result,
    ))

Dependiendo de la plataforma subyacente, usando la función incorporada y de propósito especial puede ofrecer un mejor rendimiento y precisión utilizando algoritmos de propósito especial para la base 2 que no se encuentran en la función más general.

$ python3 math_log2.py

 i   x   log2
-- ----- -----
 0   1.0   0.0
 1   2.0   1.0
 2   4.0   2.0
 3   8.0   3.0
 4  16.0   4.0
 5  32.0   5.0
 6  64.0   6.0
 7 128.0   7.0
 8 256.0   8.0
 9 512.0   9.0

log1p() calcula la serie de Newton-Mercator (el logaritmo natural de 1+x).

math_log1p.py
import math

x = 0.0000000000000000000000001
print('x       :', x)
print('1 + x   :', 1 + x)
print('log(1+x):', math.log(1 + x))
print('log1p(x):', math.log1p(x))

log1p() es más precisa para los valores de x muy cercanos a cero porque usa un algoritmo que compensa los errores de redondeo desde la adición inicial.

$ python3 math_log1p.py

x       : 1e-25
1 + x   : 1.0
log(1+x): 0.0
log1p(x): 1e-25

exp() calcula la función exponencial (e**x).

math_exp.py
import math

x = 2

fmt = '{:.20f}'
print(fmt.format(math.e ** 2))
print(fmt.format(math.pow(math.e, 2)))
print(fmt.format(math.exp(2)))

Al igual que con otras funciones de casos especiales, utiliza un algoritmo que produce resultados más precisos que el equivalente de uso general math.pow(math.e, x).

$ python3 math_exp.py

7.38905609893064951876
7.38905609893064951876
7.38905609893065040694

expm1() es el inverso de log1p(), y calcula e**x -1.

math_expm1.py
import math

x = 0.0000000000000000000000001

print(x)
print(math.exp(x) - 1)
print(math.expm1(x))

Valores pequeños de x pierden precisión cuando se realiza la resta por separado, como con log1p().

$ python3 math_expm1.py

1e-25
0.0
1e-25

Ángulos

Aunque los grados son más comúnmente utilizados en las discusiones diarias de ángulos, radianes son la unidad estándar de medida angular en la ciencia y las matemática. Un radián es el ángulo creado por dos líneas que se cruzan en el centro de un círculo, con sus extremos en la circunferencia de el círculo espaciados por un radio.

La circunferencia se calcula como 2πr, por lo que hay una relación entre radianes y π, un valor que aparece con frecuencia en cálculos trigonométricos. Esa relación lleva a radianes a ser utilizados en trigonometría y cálculo, ya que resultan en fórmulas más compactas.

Para convertir de grados a radianes, usa radianes().

math_radians.py
import math

print('{:^7} {:^7} {:^7}'.format(
    'Degrees', 'Radians', 'Expected'))
print('{:-^7} {:-^7} {:-^7}'.format(
    '', '', ''))

INPUTS = [
    (0, 0),
    (30, math.pi / 6),
    (45, math.pi / 4),
    (60, math.pi / 3),
    (90, math.pi / 2),
    (180, math.pi),
    (270, 3 / 2.0 * math.pi),
    (360, 2 * math.pi),
]

for deg, expected in INPUTS:
    print('{:7d} {:7.2f} {:7.2f}'.format(
        deg,
        math.radians(deg),
        expected,
    ))

La fórmula para la conversión es rad = deg * π / 180.

$ python3 math_radians.py

Degrees Radians Expected
------- ------- -------
      0    0.00    0.00
     30    0.52    0.52
     45    0.79    0.79
     60    1.05    1.05
     90    1.57    1.57
    180    3.14    3.14
    270    4.71    4.71
    360    6.28    6.28

Para convertir de radianes a grados, usa degrees().

math_degrees.py
import math

INPUTS = [
    (0, 0),
    (math.pi / 6, 30),
    (math.pi / 4, 45),
    (math.pi / 3, 60),
    (math.pi / 2, 90),
    (math.pi, 180),
    (3 * math.pi / 2, 270),
    (2 * math.pi, 360),
]

print('{:^8} {:^8} {:^8}'.format(
    'Radians', 'Degrees', 'Expected'))
print('{:-^8} {:-^8} {:-^8}'.format('', '', ''))
for rad, expected in INPUTS:
    print('{:8.2f} {:8.2f} {:8.2f}'.format(
        rad,
        math.degrees(rad),
        expected,
    ))

La fórmula es deg = rad * 180 / π.

$ python3 math_degrees.py

Radians  Degrees  Expected
-------- -------- --------
    0.00     0.00     0.00
    0.52    30.00    30.00
    0.79    45.00    45.00
    1.05    60.00    60.00
    1.57    90.00    90.00
    3.14   180.00   180.00
    4.71   270.00   270.00
    6.28   360.00   360.00

Trigonometría

Las funciones trigonométricas relacionan ángulos en un triángulo con las longitudes de sus lados. Aparecen en fórmulas con propiedades periódicas como armónicos, movimiento circular, o cuando se trata de ángulos. Toda las funciones trigonométricas en la biblioteca estándar toman ángulos expresados como radianes.

Dado un ángulo en un triángulo rectángulo, el seno es la relación de longitud del lado opuesto al ángulo de la hipotenusa (sin A = opuesto / hipotenusa). El coseno es la relación de la longitud de el lado adyacente a la hipotenusa (cos A = adyacente / hipotenusa). Y la tangente es la relación del lado opuesto al lado adyacente (tan A = opuesto / adyacente).

math_trig.py
import math

print('{:^7} {:^7} {:^7} {:^7} {:^7}'.format(
    'Degrees', 'Radians', 'Sine', 'Cosine', 'Tangent'))
print('{:-^7} {:-^7} {:-^7} {:-^7} {:-^7}'.format(
    '-', '-', '-', '-', '-'))

fmt = '{:7.2f} {:7.2f} {:7.2f} {:7.2f} {:7.2f}'

for deg in range(0, 361, 30):
    rad = math.radians(deg)
    if deg in (90, 270):
        t = float('inf')
    else:
        t = math.tan(rad)
    print(fmt.format(deg, rad, math.sin(rad), math.cos(rad), t))

La tangente también se puede definir como la relación del seno del ángulo a su coseno, y dado que el coseno es 0 para π/2 y 3π/2 radianes, la tangente es infinita.

$ python3 math_trig.py

Degrees Radians  Sine   Cosine  Tangent
------- ------- ------- ------- -------
   0.00    0.00    0.00    1.00    0.00
  30.00    0.52    0.50    0.87    0.58
  60.00    1.05    0.87    0.50    1.73
  90.00    1.57    1.00    0.00     inf
 120.00    2.09    0.87   -0.50   -1.73
 150.00    2.62    0.50   -0.87   -0.58
 180.00    3.14    0.00   -1.00   -0.00
 210.00    3.67   -0.50   -0.87    0.58
 240.00    4.19   -0.87   -0.50    1.73
 270.00    4.71   -1.00   -0.00     inf
 300.00    5.24   -0.87    0.50   -1.73
 330.00    5.76   -0.50    0.87   -0.58
 360.00    6.28   -0.00    1.00   -0.00

Dado un punto (x, y), la longitud de la hipotenusa para el triángulo entre los puntos [(0, 0), (x, 0), (x, y) es (x**2 + y**2) ** 1/2, y se puede calcular con hypot().

math_hypot.py
import math

print('{:^7} {:^7} {:^10}'.format('X', 'Y', 'Hypotenuse'))
print('{:-^7} {:-^7} {:-^10}'.format('', '', ''))

POINTS = [
    # simple points
    (1, 1),
    (-1, -1),
    (math.sqrt(2), math.sqrt(2)),
    (3, 4),  # 3-4-5 triangle
    # on the circle
    (math.sqrt(2) / 2, math.sqrt(2) / 2),  # pi/4 rads
    (0.5, math.sqrt(3) / 2),  # pi/3 rads
]

for x, y in POINTS:
    h = math.hypot(x, y)
    print('{:7.2f} {:7.2f} {:7.2f}'.format(x, y, h))

Los puntos en el círculo siempre tienen hipotenusa igual a 1.

$ python3 math_hypot.py

   X       Y    Hypotenuse
------- ------- ----------
   1.00    1.00    1.41
  -1.00   -1.00    1.41
   1.41    1.41    2.00
   3.00    4.00    5.00
   0.71    0.71    1.00
   0.50    0.87    1.00

La misma función se puede usar para encontrar la distancia entre dos puntos.

math_distance_2_points.py
import math

print('{:^8} {:^8} {:^8} {:^8} {:^8}'.format(
    'X1', 'Y1', 'X2', 'Y2', 'Distance',
))
print('{:-^8} {:-^8} {:-^8} {:-^8} {:-^8}'.format(
    '', '', '', '', '',
))

POINTS = [
    ((5, 5), (6, 6)),
    ((-6, -6), (-5, -5)),
    ((0, 0), (3, 4)),  # 3-4-5 triangle
    ((-1, -1), (2, 3)),  # 3-4-5 triangle
]

for (x1, y1), (x2, y2) in POINTS:
    x = x1 - x2
    y = y1 - y2
    h = math.hypot(x, y)
    print('{:8.2f} {:8.2f} {:8.2f} {:8.2f} {:8.2f}'.format(
        x1, y1, x2, y2, h,
    ))

Use la diferencia en los valores x y y para mover un punto final al origen, y luego pasa los resultados a hypot().

$ python3 math_distance_2_points.py

   X1       Y1       X2       Y2    Distance
-------- -------- -------- -------- --------
    5.00     5.00     6.00     6.00     1.41
   -6.00    -6.00    -5.00    -5.00     1.41
    0.00     0.00     3.00     4.00     5.00
   -1.00    -1.00     2.00     3.00     5.00

math también define funciones trigonométricas inversas.

math_inverse_trig.py
import math

for r in [0, 0.5, 1]:
    print('arcsine({:.1f})    = {:5.2f}'.format(r, math.asin(r)))
    print('arccosine({:.1f})  = {:5.2f}'.format(r, math.acos(r)))
    print('arctangent({:.1f}) = {:5.2f}'.format(r, math.atan(r)))
    print()

1.57 es aproximadamente igual a π/2, o 90 grados, el ángulo en que el seno es 1 y el coseno es 0.

$ python3 math_inverse_trig.py

arcsine(0.0)    =  0.00
arccosine(0.0)  =  1.57
arctangent(0.0) =  0.00

arcsine(0.5)    =  0.52
arccosine(0.5)  =  1.05
arctangent(0.5) =  0.46

arcsine(1.0)    =  1.57
arccosine(1.0)  =  0.00
arctangent(1.0) =  0.79

Funciones hiperbólicas

Funciones hiperbólicas aparecen en ecuaciones diferenciales lineales y son utilizadas cuando se trabaja con campos electromagnéticos, dinámica de fluidos, relatividad especial y otras físicas y matemáticas avanzadas.

math_hyperbolic.py
import math

print('{:^6} {:^6} {:^6} {:^6}'.format(
    'X', 'sinh', 'cosh', 'tanh',
))
print('{:-^6} {:-^6} {:-^6} {:-^6}'.format('', '', '', ''))

fmt = '{:6.4f} {:6.4f} {:6.4f} {:6.4f}'

for i in range(0, 11, 2):
    x = i / 10.0
    print(fmt.format(
        x,
        math.sinh(x),
        math.cosh(x),
        math.tanh(x),
    ))

Mientras que las funciones del coseno y del seno forman un círculo, el coseno hiperbólico y el seno hiperbólico forman la mitad de una hipérbola.

$ python3 math_hyperbolic.py

  X     sinh   cosh   tanh
------ ------ ------ ------
0.0000 0.0000 1.0000 0.0000
0.2000 0.2013 1.0201 0.1974
0.4000 0.4108 1.0811 0.3799
0.6000 0.6367 1.1855 0.5370
0.8000 0.8881 1.3374 0.6640
1.0000 1.1752 1.5431 0.7616

También están disponibles funciones hiperbólicas inversas acosh(), asinh() y atanh().

Funciones Especiales

La función de error de Gauss se usa en las estadísticas.

math_erf.py
import math

print('{:^5} {:7}'.format('x', 'erf(x)'))
print('{:-^5} {:-^7}'.format('', ''))

for x in [-3, -2, -1, -0.5, -0.25, 0, 0.25, 0.5, 1, 2, 3]:
    print('{:5.2f} {:7.4f}'.format(x, math.erf(x)))

Para la función de error, erf(-x) == -erf(x).

$ python3 math_erf.py

  x   erf(x)
----- -------
-3.00 -1.0000
-2.00 -0.9953
-1.00 -0.8427
-0.50 -0.5205
-0.25 -0.2763
 0.00  0.0000
 0.25  0.2763
 0.50  0.5205
 1.00  0.8427
 2.00  0.9953
 3.00  1.0000

La función de error complementario es 1 - erf (x).

math_erfc.py
import math

print('{:^5} {:7}'.format('x', 'erfc(x)'))
print('{:-^5} {:-^7}'.format('', ''))

for x in [-3, -2, -1, -0.5, -0.25, 0, 0.25, 0.5, 1, 2, 3]:
    print('{:5.2f} {:7.4f}'.format(x, math.erfc(x)))

La implementación de erfc() evita errores de precisión para valores pequeños de x al restar de 1.

$ python3 math_erfc.py

  x   erfc(x)
----- -------
-3.00  2.0000
-2.00  1.9953
-1.00  1.8427
-0.50  1.5205
-0.25  1.2763
 0.00  1.0000
 0.25  0.7237
 0.50  0.4795
 1.00  0.1573
 2.00  0.0047
 3.00  0.0000

Ver también