Python - abs vs fabs

107

Percebi que em python existem dois métodos semelhantes para encontrar o valor absoluto de um número:

Primeiro

abs(-5)

Segundo

import math
math.fabs(-5)

Como esses métodos diferem?

Mateusz Jagiełło
fonte

Respostas:

127

math.fabs()converte seu argumento para float se puder (se não puder, ele lança uma exceção). Em seguida, ele assume o valor absoluto e retorna o resultado como um float.

Além de flutuantes, abs()também funciona com inteiros e números complexos. Seu tipo de retorno depende do tipo de seu 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
fonte
4
absfunciona com muito mais do que apenas inteiros e flutuantes, e o tipo de resultado nem sempre é o mesmo que o argumento, por exemplo abs(3+4j).
agf
1
adicione um comentário sobre fabsdemorar mais devido à sua natureza sempre flutuante e você terá a resposta certa!
Patrick Perini
@agf: Obrigado por me lembrar dos números complexos. Por interesse, a que outras classes de coisas podem __builtin__.abs()ser aplicadas com sucesso?
NPE
5
@aix Qualquer classe definida pelo usuário que define o __abs__método mágico
agf
9

Edit: como @aix sugeriu, uma maneira melhor (mais justa) de comparar a diferença de velocidade:

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

Portanto, parece que abs()tem apenas uma ligeira vantagem de velocidade sobre os fabs()inteiros. Para flutuadores abs()e fabs()demonstre velocidade semelhante.


Além do que @aix disse, mais uma coisa a se considerar é a diferença de velocidade:

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

Então abs()é mais rápido do que math.fabs().

KZ
fonte
3
Você não está comparando maçãs com maçãs aí. Use from math import fabscom certeza e experimente os -5.0dois.
agf
Também resultados de tempo não confiáveis? Você primeiro teve abs (-5) a 102ns e, mais tarde, mostrou-o como 88,3ns. Nunca tire conclusões de uma única execução de qualquer benchmark, mesmo que internamente tente evitar os problemas como o tempo faz.
Peter Hansen
1
Mais dois pontos: ainda compara maçãs e laranjas, uma vez que abs é pesquisado nos builtins, enquanto fabs está no namespace do módulo. Faça "xabs = abs" e depois xabs (num) para remover esse efeito. Além disso, com Python 3.2 as coisas mudam um pouco e, aparentemente, abs () é um pouco mais rápido (> 2x), pelo menos em floats.
Peter Hansen
1
@PeterHansen Você está certo, são de duas execuções em diferentes cargas de sistema. Embora quando comparada dentro do mesmo conjunto de testes, a diferença relativa ainda é válida. Além disso, obrigado por apontar a diferença de namespace - eu não considerei isso. Não experimentei no 3.2, mas é bom saber! Vou atualizar minha resposta com suas sugestões um pouco mais tarde :) Obrigado novamente!
KZ
3

math.fabs()sempre retorna float, enquanto abs()pode retornar um inteiro.

Tadeck
fonte
6
abspode retornar qualquer tipo, dependendo do __abs__método especial do tipo em que é chamado.
agf
0

abs(): Retorna o valor absoluto de acordo com o argumento, ou seja, se o argumento for int, ele retornará int, se o argumento for float, ele retornará float. Também funciona em variáveis ​​complexas, ou seja, abs(a+bj)também funciona e retorna o valor absoluto, ou sejamath.sqrt(((a)**2)+((b)**2)

math.fabs(): Funciona apenas com valores inteiros ou flutuantes. Sempre retorna o valor flutuante absoluto, não importa qual seja o tipo de argumento (exceto para os números complexos).

Rahul Talole
fonte