Почему x**4.0
быстрее чем x**4
? Я использую CPython 3.5.2.
$ python -m timeit "for x in range(100):" " x**4.0"
10000 loops, best of 3: 24.2 usec per loop
$ python -m timeit "for x in range(100):" " x**4"
10000 loops, best of 3: 30.6 usec per loop
Я попытался изменить мощность, которую я поднял, чтобы увидеть, как она действует, и, например, если я поднимаю x до степени 10 или 16, он прыгает с 30 до 35, но если я поднимаю на 10,0 как поплавок, он просто движется около 24,1 ~ 4.
Я предполагаю, что это как-то связано с конвертацией с плавающей запятой и степенями 2, может быть, но я действительно не знаю.
Я заметил, что в обоих случаях степени 2 быстрее, я думаю, так как эти вычисления более понятны / просты для интерпретатора / компьютера. Но все же, с поплавками это почти не движется. 2.0 => 24.1~4 & 128.0 => 24.1~4
но 2 => 29 & 128 => 62
TigerhawkT3 отметил, что это не происходит вне цикла. Я проверил, и ситуация возникает (из того, что я видел), когда база поднимается. Есть идеи по этому поводу?
python
performance
python-3.x
python-3.5
python-internals
arieljannai
источник
источник
x**4.0
и 3.9 дляx**4
.Ответы:
int
Объекты Python 3 - это полноценный объект, разработанный для поддержки произвольного размера; в связи с этим они обрабатываются как таковые на уровне C (смотрите, как все переменные объявляются какPyLongObject *
type inlong_pow
). Это также делает их возведение в степень более хитрым и утомительным, поскольку вам нужно поиграться сob_digit
массивом, который он использует для представления его значения для его выполнения. ( Источник для смелых. - См .: Понимание распределения памяти для больших целых чисел в Python для получения дополнительной информации оPyLongObject
s.)float
Объекты Python , напротив, могут быть преобразованы вdouble
тип C (с помощьюPyFloat_AsDouble
), а операции могут выполняться с использованием этих собственных типов . Это здорово , потому что, после проверки соответствующих реберных случаев, это позволяет Python , чтобы использовать платформыpow
( C - хpow
, то есть ) для обработки фактического возведения в степени:где
iv
иiw
наши оригинальныеPyFloatObject
s как Cdouble
s.Предыдущий факт также объясняет несоответствие между Python 2 и 3, поэтому я подумал, что я тоже рассмотрю этот комментарий, потому что он интересен.
В Python 2 вы используете старый
int
объект, который отличается отint
объекта в Python 3 (всеint
объекты в 3.x имеютPyLongObject
тип). В Python 2 есть различие, которое зависит от значения объекта (или, если вы используете суффиксL/l
):<type 'int'>
Вы видите здесь делает то же самоеfloat
с делать , он получает благополучно превращается в C ,long
когда экспоненцирование выполняется на нем (int_pow
также намекает на компилятор поместил их в реестр , если он может сделать это, так что может сделать разницу) :это позволяет получить хороший прирост скорости.
Чтобы увидеть, насколько медлительны
<type 'long'>
s по сравнению с<type 'int'>
s, если вы обернулиx
имя вlong
вызове в Python 2 (по сути, заставляя его использоватьlong_pow
как в Python 3), прирост скорости исчезает:Обратите внимание, что, хотя один фрагмент преобразовывает значение
int
в,long
а другой - нет (на что указывает @pydsinger), это приведение не является движущей силой замедления. Реализацияlong_pow
есть. (Время заявления только с,long(x)
чтобы увидеть).Это оптимизатор глазка CPython, складывающий константы для вас. Вы получаете одинаковые точные значения времени в любом случае, так как нет фактических вычислений, чтобы найти результат возведения в степень, только загрузка значений:
Идентичный байт-код генерируется для
'4 ** 4.'
с той лишь разницей, чтоLOAD_CONST
загружает float256.0
вместо int256
:Так что времена совпадают.
* Все вышеперечисленное относится исключительно к CPython, эталонной реализации Python. Другие реализации могут работать по-другому.
источник
range
, поскольку синхронизация только самой**
операции не дает разницы между целыми числами и числами с плавающей точкой.4**4
так же быстро, как4**4.0
), и этот ответ не касается этого вообще.dis(compile('4 ** 4', '', 'exec'))
), поэтому время должно быть точно таким же.long(x)**2.
все еще быстрее, чемlong(x)**2
в 4-5 раз. (Не один из downvoters, хотя)<type 'long'>
типа в Python 3, вероятно, объясняется усилиями, предпринятыми для упрощения языка. Если у вас может быть один тип для представления целых чисел, он более управляем, чем два (и беспокоится о преобразовании из одного в другой, когда это необходимо, пользователи могут запутаться и т. Д.). Увеличение скорости является вторичным по отношению к этому. Раздел обоснования PEP 237 также предлагает более глубокое понимание.Если мы посмотрим на байт-код, то увидим, что выражения чисто идентичны. Единственное отличие - это тип константы, который будет аргументом
BINARY_POWER
. Так что это, безусловно, связано сint
преобразованием в число с плавающей точкой вниз по линии.Обновление: давайте посмотрим на Objects / abstract.c в исходном коде CPython:
PyNumber_Power
звонкиternary_op
, которые слишком долго, чтобы вставить здесь, так что вот ссылка .Он вызывает
nb_power
слотx
, передаваяy
в качестве аргумента.Наконец, в
float_pow()
строке 686 Objects / floatobject.c мы видим, что аргументы преобразуются в Cdouble
непосредственно перед фактической операцией:источник
float_pow
когда это не работает для медленного случая?4**4
и4**4.0
получить постоянно сложенный. Это совершенно отдельный эффект.Потому что одно правильно, другое - приближение.
источник