Python - abs vs fabs

107

Я заметил, что в python есть два похожих метода поиска абсолютного значения числа:

Первый

abs(-5)

Второй

import math
math.fabs(-5)

Чем отличаются эти методы?

Матеуш Ягелло
источник

Ответы:

127

math.fabs()преобразует свой аргумент в float, если может (если не может, генерирует исключение). Затем он принимает абсолютное значение и возвращает результат в виде числа с плавающей точкой.

Помимо чисел с плавающей запятой, abs()также работает с целыми и комплексными числами. Его возвращаемый тип зависит от типа его аргумента.

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
источник
4
absработает не только с целыми числами и числами с плавающей запятой, и тип результата не всегда совпадает с аргументом, например abs(3+4j).
agf
1
добавьте комментарий о том, что он fabsзанимает больше времени из-за его всегда плавающего характера, и вы получите правильный ответ!
Патрик Перини
@agf: Спасибо, что напомнили мне о комплексных числах. Ради интереса, к каким еще классам вещей можно __builtin__.abs()успешно применить?
NPE
5
@aix Любой определяемый пользователем класс, который определяет __abs__магический метод
agf
9

Изменить: как предложил @aix, лучший (более справедливый) способ сравнить разницу в скорости:

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

Таким образом, кажется, abs()что fabs()у целых чисел есть только небольшое преимущество в скорости . Для поплавков abs()и fabs()демонстрируйте аналогичную скорость.


В дополнение к тому, что сказал @aix, еще одна вещь, которую следует учитывать, - это разница в скорости:

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

Так abs()быстрее чем math.fabs().

KZ
источник
3
Вы здесь не сравниваете яблоки с яблоками. Используйте from math import fabsточно, и попробовать -5.0для обеих сторон .
agf
Также ненадежные результаты по времени? Сначала у вас был абс (-5) на 102 нс, а затем он был показан как 88,3 нс. Никогда не делайте выводов из одного прогона какого-либо теста, даже если он внутренне пытается избежать проблем, как это делает timeit.
Питер Хансен
1
Еще два момента: это все еще сравнивает яблоки и апельсины, так как abs ищется во встроенных командах, а fabs находится в пространстве имен модуля. Выполните «xabs = abs», затем xabs (num), чтобы удалить этот эффект. Кроме того, с Python 3.2 все немного изменилось, и, по-видимому, abs () стал немного быстрее (> 2x), по крайней мере, на float.
Питер Хансен
1
@PeterHansen. Вы правы, это из двух прогонов при разных нагрузках на систему. Хотя при сравнении в рамках одного набора тестов относительная разница все еще сохраняется. Кроме того, спасибо за указание на разницу в пространстве имен - я этого не учел. Я не пробовал на 3.2, но это хорошо! Я дополню свой ответ вашими предложениями чуть позже :) Еще раз спасибо!
KZ
3

math.fabs()всегда возвращает число с плавающей запятой, а abs()может возвращать целое число.

Тадек
источник
6
absможет возвращать любой тип, в зависимости от __abs__специального метода вызываемого типа.
agf
0

abs(): Возвращает абсолютное значение в соответствии с аргументом, т.е. если аргумент int, то он возвращает int, если аргумент float, он возвращает float. Также он работает со сложной переменной, т.е. abs(a+bj)также работает и возвращает абсолютное значение, т.е.math.sqrt(((a)**2)+((b)**2)

math.fabs(): Работает только с целыми числами или значениями с плавающей запятой. Всегда возвращает абсолютное значение с плавающей запятой независимо от типа аргумента (кроме комплексных чисел).

Рахул Талоле
источник