TL;DR:
numpy.cos()
работает на 30% дольше для определенных чисел (например, ровно 24000.0). Добавление небольшой дельты (+0.01) приводит к numpy.cos()
работе numpy.cos()
.
Понятия не имею почему.
Я наткнулся на странную проблему во время моей работы с numpy
. Я проверял работу кеша и случайно сделал неправильный график - как время numpy.cos(X)
зависит от X
Вот мой модифицированный код (скопированный из моего блокнота Jupyter):
import numpy as np
import timeit
st = 'import numpy as np'
cmp = []
cmp_list = []
left = 0
right = 50000
step = 1000
# Loop for additional average smoothing
for _ in range(10):
cmp_list = []
# Calculate np.cos depending on its argument
for i in range(left, right, step):
s=(timeit.timeit('np.cos({})'.format(i), number=15000, setup=st))
cmp_list.append(int(s*1000)/1000)
cmp.append(cmp_list)
# Calculate average times
av=[np.average([cmp[i][j] for i in range(len(cmp))]) for j in range(len(cmp[0]))]
# Draw the graph
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(1, 1, 1)
plt.plot(range(left, right, step), av, marker='.')
plt.show()
График выглядел так:
Сначала я подумал, что это просто случайный сбой. Я пересчитал свои камеры, но результат был почти таким же. Поэтому я начал играть с параметрами step
, с количеством вычислений и средней длиной списка. Но все это никак не повлияло на это число:
И еще ближе:
После этого range
был бесполезен (он не может np.cos
с поплавками), поэтому я вычислил np.cos
вручную:
print(timeit.timeit('np.cos({})'.format(24000.01),number=5000000,setup=st))
print(timeit.timeit('np.cos({})'.format(24000.00),number=5000000,setup=st))
print(timeit.timeit('np.cos({})'.format(23999.99),number=5000000,setup=st))
И результат был:
3.4297256958670914
4.337243619374931
3.4064380447380245
np.cos()
рассчитывает ровно 24000,00 на 30% дольше, чем 24000.01!
Были и другие странные цифры вроде этого (где-то около 500000, я точно не помню).
Я просмотрел numpy
документацию, ее исходный код, и он ничего не имел об этом эффекте. Я знаю, что тригонометрические функции используют несколько алгоритмов, в зависимости от размера значения, точности и т.д., Но меня смущает, что точные числа можно вычислить намного дольше.
Почему np.cos()
имеет такой странный эффект? Это какой-то побочный эффект процессора (потому что numpy.cos
использует C-функции, которые зависят от процессоров)? У меня установлены Intel Core i5 и Ubuntu, если это кому-то поможет.
Редактировать 1: я пытался воспроизвести его на другом компьютере с AMD Ryzen 5. Результаты просто нестабильны. Вот графики для трех последовательных прогонов одного и того же кода:
import numpy as np
import timeit
s = 'import numpy as np'
times = []
x_ranges = np.arange(23999, 24001, 0.01)
for x in x_ranges:
times.append(timeit.timeit('np.cos({})'.format(x), number=100000, setup=s))
# ---------------
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
plt.plot(x_ranges, times)
plt.show()
Ну, есть некоторые паттерны (например, в основном непротиворечивая левая часть и непоследовательная правая часть), но она сильно отличается от процессоров Intel. Похоже, что это действительно особые аспекты процессоров, а поведение AMD гораздо более предсказуемо в своей неопределенности :)
PS @WarrenWeckesser спасибо за функцию '' np.arange '' '. Это действительно полезно, но это ничего не меняет в результатах, как и ожидалось.