Python - ABS vs fabs

107

J'ai remarqué qu'en python, il existe deux méthodes similaires pour trouver la valeur absolue d'un nombre:

Première

abs(-5)

Seconde

import math
math.fabs(-5)

En quoi ces méthodes diffèrent-elles?

Mateusz Jagiełło
la source

Réponses:

127

math.fabs()convertit son argument en float s'il le peut (s'il ne le peut pas, il lève une exception). Il prend ensuite la valeur absolue et renvoie le résultat sous forme de flottant.

En plus des flottants, abs()fonctionne également avec des entiers et des nombres complexes. Son type de retour dépend du type de son argument.

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
la source
4
absfonctionne avec bien plus que des entiers et des flottants, et le type de résultat n'est pas toujours le même que l'argument, par exemple abs(3+4j).
agf
1
ajoutez un commentaire sur le fait de fabsprendre plus de temps en raison de sa nature toujours flottante et vous avez la bonne réponse!
Patrick Perini
@agf: Merci de me rappeler les nombres complexes. Par intérêt, quelles autres classes de choses peuvent __builtin__.abs()être appliquées avec succès?
NPE
5
@aix Toute classe définie par l'utilisateur qui définit la __abs__méthode magique
agf
9

Edit: comme @aix l'a suggéré, une meilleure façon (plus juste) de comparer la différence de vitesse:

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

Il semble donc qu'il abs()n'y ait qu'un léger avantage de vitesse par rapport fabs()aux nombres entiers. Pour les flotteurs abs()et fabs()démontrer une vitesse similaire.


En plus de ce que @aix a dit, une autre chose à considérer est la différence de vitesse:

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

C'est donc abs()plus rapide que math.fabs().

KZ
la source
3
Vous ne comparez pas les pommes aux pommes ici. Utilisez from math import fabsbien sûr et essayez les -5.0deux.
agf
Des résultats de synchronisation non fiables également? Vous avez d'abord eu des abdos (-5) à 102ns, puis montrez-les plus tard comme 88,3ns. Ne tirez jamais de conclusions à partir d'une seule exécution d'un benchmark, même s'il essaie en interne d'éviter les problèmes comme le fait le temps.
Peter Hansen
1
Deux autres points: cela compare toujours les pommes et les oranges, puisque abs est recherché dans les builtins, tandis que fabs est dans l'espace de noms du module. Faites "xabs = abs" puis xabs (num) pour supprimer cet effet. De plus, avec Python 3.2, les choses changent un peu et apparemment abs () est un peu plus rapide (> 2x), du moins sur les flottants.
Peter Hansen
1
@PeterHansen Vous avez raison, ceux-ci proviennent de deux exécutions sous des charges système différentes. Bien que comparée dans le même ensemble de tests, la différence relative est toujours valide. Merci également d'avoir souligné la différence d'espace de noms - je n'ai pas pensé à cela. Je ne l'ai pas essayé sur 3.2, mais c'est bon à savoir! Je mettrai à jour ma réponse avec vos suggestions un peu plus tard :) Merci encore!
KZ
3

math.fabs()renvoie toujours float, tandis que abs()peut renvoyer un entier.

Tadeck
la source
6
abspeut renvoyer n'importe quel type, selon la __abs__méthode spéciale du type sur lequel il est appelé.
agf
0

abs(): Renvoie la valeur absolue selon l'argument, c'est-à-dire que si l'argument est int alors il retourne int, si l'argument est float, il renvoie float. Il fonctionne également sur des variables complexes, c'est-à-dire abs(a+bj)fonctionne également et renvoie une valeur absolue, c'est-à-diremath.sqrt(((a)**2)+((b)**2)

math.fabs(): Cela ne fonctionne que sur les valeurs entières ou flottantes. Renvoie toujours la valeur flottante absolue quel que soit le type d'argument (sauf pour les nombres complexes).

Rahul Talole
la source