Python - abs vs fabs

107

Noté que en Python hay dos métodos de búsqueda similares para encontrar el valor absoluto de un número:

primero

abs(-5)

Segundo

import math
math.fabs(-5)

¿En qué se diferencian estos métodos?

Mateusz Jagiełło
fuente

Respuestas:

127

math.fabs()convierte su argumento en flotante si puede (si no puede, lanza una excepción). Luego toma el valor absoluto y devuelve el resultado como flotante.

Además de flotantes, abs()también funciona con números enteros y complejos. Su tipo de retorno depende del tipo de argumento.

In [7]: type(abs(-2))
Out[7]: int

In [8]: type(abs(-2.0))
Out[8]: float

In [9]: type(abs(3+4j))
Out[9]: float

In [10]: type(math.fabs(-2))
Out[10]: float

In [11]: type(math.fabs(-2.0))
Out[11]: float

In [12]: type(math.fabs(3+4j))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/home/npe/<ipython-input-12-8368761369da> in <module>()
----> 1 type(math.fabs(3+4j))

TypeError: can't convert complex to float
NPE
fuente
4
absfunciona con mucho más que números enteros y flotantes, y el tipo de resultado no siempre es el mismo que el argumento, por ejemplo abs(3+4j).
agf
1
agregue un comentario sobre fabstomar más tiempo debido a su naturaleza siempre flotante y tendrá la respuesta correcta.
Patrick Perini
@agf: Gracias por recordarme los números complejos. Por interés, ¿a qué otras clases de cosas se __builtin__.abs()pueden aplicar con éxito?
NPE
5
@aix Cualquier clase definida por el usuario que define el __abs__método mágico
agf
9

Editar: como sugirió @aix, una forma mejor (más justa) de comparar la diferencia de velocidad:

In [1]: %timeit abs(5)
10000000 loops, best of 3: 86.5 ns per loop

In [2]: from math import fabs

In [3]: %timeit fabs(5)
10000000 loops, best of 3: 115 ns per loop

In [4]: %timeit abs(-5)
10000000 loops, best of 3: 88.3 ns per loop

In [5]: %timeit fabs(-5)
10000000 loops, best of 3: 114 ns per loop

In [6]: %timeit abs(5.0)
10000000 loops, best of 3: 92.5 ns per loop

In [7]: %timeit fabs(5.0)
10000000 loops, best of 3: 93.2 ns per loop

In [8]: %timeit abs(-5.0)
10000000 loops, best of 3: 91.8 ns per loop

In [9]: %timeit fabs(-5.0)
10000000 loops, best of 3: 91 ns per loop

Entonces, parece que abs()solo tiene una ligera ventaja de velocidad sobre los fabs()números enteros. Para flotadores abs()y fabs()demostrar una velocidad similar.


Además de lo que ha dicho @aix, una cosa más a considerar es la diferencia de velocidad:

In [1]: %timeit abs(-5)
10000000 loops, best of 3: 102 ns per loop

In [2]: import math

In [3]: %timeit math.fabs(-5)
10000000 loops, best of 3: 194 ns per loop

Entonces abs()es más rápido que math.fabs().

KZ
fuente
3
No estás comparando manzanas con manzanas allí. Úselo from math import fabscon seguridad y pruebe -5.0con ambos.
agf
¿También resultados de sincronización poco fiables? Primero tenías abdominales (-5) a 102 ns, luego lo mostraste como 88.3 ns. Nunca saque conclusiones de una sola ejecución de cualquier punto de referencia, incluso si internamente intenta evitar los problemas como lo hace el tiempo.
Peter Hansen
1
Dos puntos más: esto todavía compara manzanas y naranjas, ya que abs se busca en los archivos incorporados, mientras que fabs está en el espacio de nombres del módulo. Haga "xabs = abs" y luego xabs (num) para eliminar ese efecto. Además, con Python 3.2 las cosas cambian bastante y aparentemente abs () es bastante más rápido (> 2x), al menos en flotantes.
Peter Hansen
1
@PeterHansen Tienes razón, son de dos ejecuciones con cargas de sistema diferentes. Aunque cuando se compara dentro del mismo conjunto de pruebas, la diferencia relativa sigue siendo válida. Además, gracias por señalar la diferencia de espacio de nombres, no lo consideré. No lo he probado en 3.2, ¡pero es bueno saberlo! Actualizaré mi respuesta con sus sugerencias un poco más tarde :) ¡Gracias de nuevo!
KZ
3

math.fabs()siempre devuelve float, mientras que abs()puede devolver un entero.

Tadeck
fuente
6
abspuede devolver cualquier tipo, dependiendo del __abs__método especial del tipo al que se llama.
agf
0

abs(): Devuelve el valor absoluto según el argumento, es decir, si el argumento es int, entonces devuelve int, si el argumento es float, devuelve float. También funciona en variables complejas, es decir, abs(a+bj)también funciona y devuelve valor absoluto, es decirmath.sqrt(((a)**2)+((b)**2)

math.fabs(): Solo funciona con valores enteros o flotantes. Siempre devuelve el valor flotante absoluto sin importar cuál sea el tipo de argumento (excepto para los números complejos).

Rahul Talole
fuente