2015-08-06 24 views
8

Ich möchte einen vektorisierten Weg finden, um die kumulativen Summen eines Vektors zu berechnen, aber mit oberen und unteren Grenzen.cumsum mit oberen und unteren Grenzen?

In meinem Fall enthält die Eingabe nur 1 und -1. Sie können diese Annahme in Ihrer Antwort verwenden. Natürlich ist auch eine allgemeinere Lösung willkommen.

Zum Beispiel:

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 

Wenn die kumulative Summe der oberen Grenze (am dritten Element) erreicht hat, wird es nicht mehr erhöhen. Ebenso, wenn die kumulative Summe die untere Grenze erreicht (am 7. Element), wird sie nicht mehr abnehmen. Eine For-Loop-Version wäre wie folgt:

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 

Haben Sie irgendwelche Ideen?

+0

Ich verstehe nicht ganz, das Beispiel Ausgabe, die Sie gezeigt haben. Kannst du ausführlicher sein und erklären, wie du zu deinem gewünschten Output gekommen bist? Wie genau spielen die oberen und unteren Grenzen mit deiner "Cumsum" -Funktion zusammen? – rayryeng

+1

Enthält 'x' nur' 1's und -1's? – Divakar

+0

@BenW entweder Grenzen angeben, was 'x' enthalten kann, oder wählen Sie ein repräsentativeres' x'. Erstens muss es mehr als "1" über und/oder unter die Grenzen gehen, es muss mehr als einmal die gleiche Grenze überschreiten und am wichtigsten, wie Divakar erwähnt, wenn "x" andere Zahlen enthalten kann, bitte einige – Dan

Antwort

5

Dies ist eine etwas hackish Lösung, aber vielleicht erwähnenswert.

Sie können die Summe tun, um einen Signed Integer-Datentyp und nutzen die inhärenten Grenzen dieses Datentypen. Damit dies funktioniert, muss die Eingabe in diesen Integer-Typ konvertiert und mit dem entsprechenden Faktor multipliziert werden, und ein erster Offset muss angewendet werden. Der Faktor und der Offset werden in Abhängigkeit von lower und upper gewählt. Nach cumsum werden Multiplikation und Offset rückgängig gemacht, um das gewünschte Ergebnis zu erhalten.

In Ihrem Beispiel genügt der Datentyp int8; und der erforderliche Faktor und Offset ist 85 und -128 jeweils:

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 

die gibt

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

Ich werde Ihnen keine magisch vektorisierte Möglichkeit bieten, dies zu tun, aber ich werde Ihnen einige Daten zur Verfügung stellen, die Ihnen wahrscheinlich helfen werden, mit Ihrer Arbeit weiterzumachen.

Ihre Funktion ist sehr schnell!

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. 

Ich bezweifle wirklich, das ist dein Engpass. Haben Sie versucht profiling the code?

Verwandte Themen