2015-08-06 15 views
8

Mi piacerebbe trovare un modo vettoriale per calcolare le somme cumulative di un vettore, ma con i limiti superiore e inferiore.cumsum con limiti superiore e inferiore?

Nel mio caso, l'input contiene solo 1 e -1. Puoi usare questa ipotesi nella tua risposta. Naturalmente, una soluzione più generale è anche benvenuta.

Ad esempio:

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 

Quando la somma cumulativa raggiunge il limite superiore (al 3 ° elemento), non aumenterà più. Allo stesso modo, quando la somma cumulativa raggiunge il limite inferiore (al settimo elemento), non diminuirà più. Una versione for-loop sarebbe così:

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 

Avete qualche idea?

+0

io non capisco l'uscita esempio che avete mostrato. Puoi essere più dettagliato e spiegare come sei arrivato all'output desiderato? In che modo esattamente i limiti superiore e inferiore entrano in gioco con la funzione "cumsum'"? – rayryeng

+1

'x' contiene solo" 1's "e" -1's "? – Divakar

+0

@BenW o specifica i limiti su cosa 'x' può contenere o scegliere un' x' più rappresentativo. In primo luogo, devi andare oltre "1" sopra e/o sotto i limiti, avere lo stesso limite più di una volta e, cosa più importante come dice Divakar, se 'x' può contenere altri numeri per favore includi alcuni – Dan

risposta

5

Questa è un po 'la soluzione hackish, ma forse vale la pena menzionarla.

Si può fare la somma con un intero con segno tipo di dati, e di sfruttare i limiti inerenti di quel tipo di dati. Affinché ciò funzioni, l'input deve essere convertito in quel tipo intero e moltiplicato per il fattore appropriato e deve essere applicato uno iniziale. Il fattore e l'offset sono scelti in funzione di lower e upper. Dopo cumsum, la moltiplicazione e l'offset vengono annullati per ottenere il risultato desiderato.

Nell'esempio, il tipo di dati int8 è sufficiente; e il fattore di richiesta e di offset sono 85 e -128 rispettivamente:

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 

che dà

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

Non ti fornirò un modo magico per farlo, ma ti fornirò alcuni dati che probabilmente ti aiuteranno a proseguire il tuo lavoro.

La tua funzione cumsumlim è molto veloce!

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. 

Ho davvero il dubbio che questo sia il collo di bottiglia. Hai provato profiling the code?