Я смотрел на источник sorted_containers и был удивлен, увидев эту строку:
self._load, self._twice, self._half = load, load * 2, load >> 1
Здесь load
представляет собой целое число. Зачем использовать бит-сдвиг в одном месте и умножение в другом? Кажется разумным, что смещение битов может быть быстрее, чем интегральное деление на 2, но почему бы не заменить умножение на сдвиг? Я сравнивал следующие случаи:
- (раз, делить)
- (сдвиг, сдвиг)
- (раз, сдвиг)
- (сдвиг, деление)
и обнаружил, что # 3 последовательно быстрее других альтернатив:
# self._load, self._twice, self._half = load, load * 2, load >> 1
import random
import timeit
import pandas as pd
x = random.randint(10 ** 3, 10 ** 6)
def test_naive():
a, b, c = x, 2 * x, x // 2
def test_shift():
a, b, c = x, x << 1, x >> 1
def test_mixed():
a, b, c = x, x * 2, x >> 1
def test_mixed_swapped():
a, b, c = x, x << 1, x // 2
def observe(k):
print(k)
return {
'naive': timeit.timeit(test_naive),
'shift': timeit.timeit(test_shift),
'mixed': timeit.timeit(test_mixed),
'mixed_swapped': timeit.timeit(test_mixed_swapped),
}
def get_observations():
return pd.DataFrame([observe(k) for k in range(100)])
Вопрос:
Является ли мой тест действительным? Если да, то почему (умножить, сдвинуть) быстрее, чем (сдвиг, сдвиг)?
Я запускаю Python 3.5 на Ubuntu 14.04.
редактировать
Выше оригинальная постановка вопроса. Дэн Гетц дает отличное объяснение в своем ответе.
Для полноты здесь приведены примеры иллюстраций для больших x
когда оптимизация умножения не применяется.