2015-08-06 6 views
8

Я бы хотел найти векторизованный способ для вычисления совокупных сумм вектора, но с верхним и нижним пределом.cumsum с верхним и нижним пределами?

В моем случае вход содержит только 1 и -1. Вы можете использовать это предположение в своем ответе. Конечно, более общее решение также приветствуется.

Например:

x  = [1 1 1 1 -1 -1 -1 -1 -1 -1]; 
upper = 3; 
lower = 0; 
s  = cumsum(x)     %// Ordinary cumsum. 
s = 
    1  2  3  4  3  2  1  0 -1 -2 

y  = cumsumlim(x, upper, lower) %// Cumsum with limits. 
y = 
    1  2  3  3  2  1  0  0  0  0 
       ^     ^
       |      | 
      upper limit    lower limit 

Когда накопленная сумма достигает верхнего предела (на 3-й элемент), он не будет больше расти. Аналогично, когда суммарная сумма достигает нижнего предела (на 7-м элементе), она больше не будет уменьшаться. Версия для петли будет такой:

function y = cumsumlim(x, upper, lower) 

y = zeros(size(x)); 
y(1) = x(1); 

for i = 2 : numel(x) 
    y(i) = y(i-1) + x(i); 
    y(i) = min(y(i), upper); 
    y(i) = max(y(i), lower); 
end 

end 

У вас есть идеи?

+0

Я не совсем понимаю пример вывода вы показали. Можете ли вы быть более подробными и объяснить, как вы достигли желаемого результата? Как именно верхний и нижний пределы вступают в игру с вашей функцией «cumsum»? – rayryeng

+1

Есть ли '' '' '' '' '' и '-1''? – Divakar

+0

@BenW либо укажет ограничения на то, что 'x' может содержать, либо выбрать более представительный' x'. Во-первых, если он превысит «1» выше и/или ниже пределов, допустите ли он один и тот же предел более одного раза и, самое главное, как упоминает Дивакар, если «х» может содержать другие номера, пожалуйста, включите некоторые – Dan

ответ

5

Это несколько хакерский решение, но, возможно, стоит упомянуть.

Вы можете сделать сумму, используя тип данных подписали целое и использовать ограничения, присущие этого типа данных. Чтобы это сработало, вход необходимо преобразовать в этот целочисленный тип и умножить на соответствующий фактор, и должно быть применено начальное смещение. Коэффициент и смещение выбираются в зависимости от lower и upper. После cumsum умножение и смещение отменены, чтобы получить желаемый результат.

В вашем примере достаточно данных типа int8; и требуемый коэффициент и смещение 85 и -128 соответственно:

x = [1 1 1 1 -1 -1 -1 -1 -1 -1]; 
result = cumsum([-128 int8(x)*85]); %// integer sum, with factor and initial offset 
result = (double(result(2:end))+128)/85; %// undo factor and offset 

который дает

result = 
    1  2  3  3  2  1  0  0  0  0 
4

Я не дам вам волшебный векторный способ сделать это, но я предоставлю вам некоторые данные, которые, вероятно, помогут вам справиться с вашей работой.

Ваша cumsumlim функция очень быстро!

tic 
for ii = 1:100 
    y = cumsumlim(x,3,0); 
end 
t = toc; 
disp(['Length of vector: ' num2str(numel(x))]) 
disp(['Total time for one execution: ' num2str(t*10), ' ms.']) 
Length of vector: 65000 
Total time for one execution: 1.7965 ms. 

Я действительно сомневаюсь, что это ваше узкое место. Вы пробовали profiling the code?

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