Python - abs vs fabs

107

Ich habe festgestellt, dass es in Python zwei ähnlich aussehende Methoden gibt, um den absoluten Wert einer Zahl zu ermitteln:

Zuerst

abs(-5)

Zweite

import math
math.fabs(-5)

Wie unterscheiden sich diese Methoden?

Mateusz Jagiełło
quelle

Antworten:

127

math.fabs()konvertiert sein Argument in float, wenn es kann (wenn es nicht kann, löst es eine Ausnahme aus). Es nimmt dann den absoluten Wert und gibt das Ergebnis als float zurück.

Funktioniert neben Floats abs()auch mit Ganzzahlen und komplexen Zahlen. Der Rückgabetyp hängt vom Typ des Arguments ab.

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/alexei/<ipython-input-12-8368761369da> in <module>()
----> 1 type(math.fabs(3+4j))

TypeError: can't convert complex to float
NPE
quelle
4
absfunktioniert mit weit mehr als nur ganzen Zahlen und Gleitkommazahlen, und der Ergebnistyp ist nicht immer derselbe wie das Argument, z abs(3+4j).
Agf
1
Fügen Sie in einem Kommentar hinzu, fabsdass es aufgrund seiner immer schwebenden Natur länger dauert, und Sie haben die richtige Antwort!
Patrick Perini
@agf: Danke, dass du mich an komplexe Zahlen erinnert hast. Auf welche anderen Klassen von Dingen kann aus Interesse __builtin__.abs()erfolgreich angewendet werden?
NPE
5
@aix Jede benutzerdefinierte Klasse, die die __abs__magische Methode definiert
agf
9

Bearbeiten: Wie @aix vorgeschlagen hat, eine bessere (fairere) Möglichkeit, den Geschwindigkeitsunterschied zu vergleichen:

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

Es scheint also abs()nur einen geringen Geschwindigkeitsvorteil gegenüber fabs()ganzen Zahlen zu haben. Für Schwimmer abs()und fabs()zeigen ähnliche Geschwindigkeit.


Zusätzlich zu dem, was @aix gesagt hat, ist der Geschwindigkeitsunterschied noch zu berücksichtigen:

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

Ist abs()also schneller als math.fabs().

KZ
quelle
3
Sie vergleichen dort keine Äpfel mit Äpfeln. Verwenden Sie es from math import fabsauf jeden Fall und versuchen Sie es -5.0für beide.
Agf
Auch unzuverlässige Timing-Ergebnisse? Sie hatten zuerst abs (-5) bei 102 ns und zeigten es später als 88,3 ns. Ziehen Sie niemals Schlussfolgerungen aus einem einzigen Durchlauf eines Benchmarks, auch wenn dieser intern versucht, die Probleme so zu vermeiden, wie es die Zeit tut.
Peter Hansen
1
Zwei weitere Punkte: Hier werden immer noch Äpfel und Orangen verglichen, da abs in den Builtins nachgeschlagen wird, während sich fabs im Modul-Namespace befindet. Führen Sie "xabs = abs" und dann xabs (num) aus, um diesen Effekt zu entfernen. Außerdem ändern sich die Dinge mit Python 3.2 ziemlich stark und anscheinend ist abs () ziemlich viel schneller (> 2x), zumindest auf Floats.
Peter Hansen
1
@PeterHansen Sie haben Recht, diese stammen aus zwei Läufen unter unterschiedlichen Systemlasten. Beim Vergleich innerhalb derselben Testreihe bleibt der relative Unterschied jedoch gültig. Vielen Dank auch für den Hinweis auf den Unterschied im Namespace - das habe ich nicht berücksichtigt. Ich habe es auf 3.2 noch nicht ausprobiert, aber das ist gut zu wissen! Ich werde meine Antwort etwas später mit Ihren Vorschlägen aktualisieren :) Nochmals vielen Dank!
KZ
3

math.fabs()Gibt immer float zurück, während abs()Integer zurückgegeben werden kann.

Tadeck
quelle
6
abskann einen beliebigen Typ zurückgeben, abhängig von der __abs__speziellen Methode des Typs, für den er aufgerufen wird.
Agf
0

abs(): Gibt den absoluten Wert gemäß dem Argument zurück, dh wenn das Argument int ist, gibt es int zurück. Wenn das Argument float ist, gibt es float zurück. Es funktioniert auch mit komplexen Variablen, dh abs(a+bj)es funktioniert auch und gibt den absoluten Wert zurück, d. H.math.sqrt(((a)**2)+((b)**2)

math.fabs(): Es funktioniert nur mit den Integer- oder Float-Werten. Gibt immer den absoluten Gleitkommawert zurück, unabhängig vom Argumenttyp (mit Ausnahme der komplexen Zahlen).

Rahul Talole
quelle