Ваше объявление float содержит две части:
timeRemaining
имеет тип float
. 0.58
к этой переменной. Проблема возникает в части 2.
Правая часть оценивается сама по себе. Согласно спецификации C #, число, содержащее десятичную точку, которая не имеет суффикса, интерпретируется как double
.
Итак, теперь мы имеем значение double
, которое мы хотим присвоить переменная типа float
. Для этого должно быть неявное преобразование из double
в float
. Нет такого преобразования, потому что вы можете (и в этом случае делать) потерять информацию в процессе преобразования.
Причина в том, что значение, используемое компилятором, на самом деле не 0.58, но с плавающей запятой значение, самое близкое к 0,58, которое составляет 0,57999999999999978655962351581366 ... для double
и ровно 0,579999946057796478271484375 для float
.
Строго говоря, f
не требуется. Вы можете избежать использования суффикса f
, выставив значение в значение float
:
float timeRemaining = (float)0.58;
Количество элементов в корзине b
- это количество элементов <= b.end
минус количество элементов < b.start
.
Таким образом, вы можете создать starts
массив бинов, отсортированных по началу, и ends
массив бинов, отсортированных по концу. Затем пройдитесь по всем 3 массивам в шаге. Когда вы продвигаетесь после каждого x
в a
, продвигайтесь дальше, начиная с x < b.start
и , вычитая position_in_a
из числа для этого бина. Затем продвиньтесь до конца с помощью x <= b.end
и и добавьте position_in_a
к счету для этого бина.
Общая сложность составляет O (N log N), где преобладает сортировка начального и конечного массивов. Ходить по 3 массивам и корректировать счет - O (N).
В своем коде вы генерируете массив уже отсортированных бинов, так что если вы можете сделать это, то можете пропустить этап сортировки, и общая сложность равна O (a.length + bin_count). Я бы не стал даже создавать этот массив, поскольку вы можете легко рассчитать начальное и конечное значения по индексу.
Примерно так (?):
def sliding_count(a, nx0, nx1, window):
bin0 = np.arange(nx0,nx1,1)
bin1 = bin0 + window
count = np.zeros((nx1-nx0), dtype=int)
for j in range(nx1-nx0):
count[j] = np.sum(a<=bin1[j]) - np.sum(a<bin0[j])
return count
#---- main ---------------
nx0, nx1, window = 0, 11, 10
a = np.array([1, 5, 8, 11, 14, 19])
sliding_count(a, nx0, nx1, window)
array([3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3])
Я не проверял код для nx0> 0 и step> 1 в bin0 = np.arange (nx0, nx1,1) . Таким образом, длина цикла for должна быть изменена для таких случаев.
import numpy as np
def alt(a, end, window, start=0, step=1):
bin_starts = np.arange(start, end+1-window, step)
bin_ends = bin_starts + window
last_index = np.searchsorted(a, bin_ends, side='right')
first_index = np.searchsorted(a, bin_starts, side='left')
return last_index - first_index
def sliding_count(a, end, window, start=0, step=1):
bins = [(x, x + window) for x in range(start, (end + 1) - window, step)]
counts = np.zeros(len(bins))
for i, rng in enumerate(bins):
count = len(a[np.where(np.logical_and(a>=rng[0], a<=rng[1]))])
counts[i] = count
return counts
a = np.array([1, 5, 8, 11, 14, 19])
end = 20
window = 10
print(sliding_count(a, end, window))
# [3. 4. 3. 3. 4. 4. 3. 3. 3. 3. 3.]
print(alt(a, end, window))
# [3 4 3 3 4 4 3 3 3 3 3]
Генерация начальных и конечных значений бинов:
In [73]: bin_starts = np.arange(start, end+1-window, step); bin_starts
Out[73]: array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
In [74]: bin_ends = bin_starts + window; bin_ends
Out[74]: array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20])
Поскольку a
в отсортированном порядке, вы можете использовать np.searchsorted
найти первый и последний индекс в bin_starts
и bin_ends
, где подходит каждое значение в a
:
In [75]: last_index = np.searchsorted(a, bin_ends, side='right'); last_index
Out[75]: array([3, 4, 4, 4, 5, 5, 5, 5, 5, 6, 6])
In [76]: first_index = np.searchsorted(a, bin_starts, side='left'); first_index
Out[76]: array([0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3])
count
- это просто разница в индексах:
In [77]: last_index - first_index
Out[77]: array([3, 4, 3, 3, 4, 4, 3, 3, 3, 3, 3])
Вот перфплот , сравнивающий производительность alt
с sliding_count
как функцию длины a
:
import perfplot
def make_array(N):
a = np.random.randint(10, size=N)
a = a.cumsum()
return a
def using_sliding(a):
return sliding_count(a, end, window)
def using_alt(a):
return alt(a, end, window)
perfplot.show(
setup=make_array,
kernels=[using_sliding, using_alt],
n_range=[2**k for k in range(22)],
logx=True,
logy=True,
xlabel='len(a)')
Perfplot также проверяет, что значение, возвращаемое using_sliding
, равно значению, возвращенному using_alt
.
Идея Мэтта Тиммерманса , « вычесть position_in_a
из подсчета для этого бина » привела в действие это решение.