2015-12-07 2 views
2

Согласно this page, один из способов вычислить целое абсолютное значение (abs) без ветвления в выглядит следующим образом:abs (v) быстрее, чем (v + mask)^маска в python?

int v;   // we want to find the absolute value of v 
unsigned int r; // the result goes here 
int const mask = v >> sizeof(int) * CHAR_BIT - 1; 

r = (v + mask)^mask; 

Из любопытства, я хотел сравнить его с abs() функции в Python:

> python -m timeit "v = -13" "r = abs(v)" 
10000000 loops, best of 3: 0.119 usec per loop 
> python -m timeit "v = -13" "mask = v >> 23" "r = (v + mask)^mask" 
10000000 loops, best of 3: 0.18 usec per loop 

Кажется, что abs() имеет лучшую производительность, чем побитовые операции. Зачем? Или я что-то пропустил в своем тестовом коде?

Более подробная информация о вышеуказанных тестовых кодах:

mask = v >> 23, из-за размером v является 24 через sys.getsizeof(v).

+2

Помните есть весь слой абстракции объектов Python между вашим кодом и базовым кодом C (предполагая CPython). Таким образом, микрооптимизации, такие как бит-хакинг, не являются надежным способом повышения производительности. – jonrsharpe

+1

Аналогично 'sys.getsizeof' сообщает вам о размере объекта Python, а не о количестве бит, необходимых для представления целого. – jonrsharpe

ответ

3

IPython Notebook упрощает синхронизацию. Весь код сразу после %%timeit - это установочный код. Я вынула задание v также:

%%timeit v = -13 
abs(v) 

10000000 loops, best of 3: 94.8 ns per loop 


%%timeit v = -13;mask = v >> 23 
(v + mask)^mask 

1000000 loops, best of 3: 182 ns per loop 

Похоже abs действительно в два раза быстрее.

Глядя на байт-код может помочь, чтобы получить чувство, что происходит:

import dis 

для abs:

dis.dis(""" 
v = -13 
r = abs(v)""") 

2   0 LOAD_CONST    2 (-13) 
       3 STORE_NAME    0 (v) 

    3   6 LOAD_NAME    1 (abs) 
       9 LOAD_NAME    0 (v) 
      12 CALL_FUNCTION   1 (1 positional, 0 keyword pair) 
      15 STORE_NAME    2 (r) 
      18 LOAD_CONST    1 (None) 
      21 RETURN_VALUE 

и другой подход:

dis.dis(""" 
v = -13 
mask = v >> 23 
r = (v + mask)^mask 
""") 

    2   0 LOAD_CONST    3 (-13) 
       3 STORE_NAME    0 (v) 

    3   6 LOAD_NAME    0 (v) 
       9 LOAD_CONST    1 (23) 
      12 BINARY_RSHIFT 
      13 STORE_NAME    1 (mask) 

    4   16 LOAD_NAME    0 (v) 
      19 LOAD_NAME    1 (mask) 
      22 BINARY_ADD 
      23 LOAD_NAME    1 (mask) 
      26 BINARY_XOR 
      27 STORE_NAME    2 (r) 
      30 LOAD_CONST    2 (None) 
      33 RETURN_VALUE 
+0

Также обратите внимание, что бинарные операторы могут снова вызвать (дорогие!) Методы поиска, поскольку эти операторы могли бы быть переопределены, если типы не встроены. Я не уверен, способен ли компилятор python вывести его в этом случае. –

+1

Я не вижу, какую полезную информацию предоставляет байт-код. Это просто прямой перевод Python. Вы все еще не знаете, что делает функция 'abs', например. – interjay

Смежные вопросы