PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Matlab: array als Spalte und nciht als Zeile


JFZ
2009-10-08, 20:32:06
Hi,

ich darf gerade eine Auswertung mit Matlab machen und müsste ein Array befüllen. Momentan mache ich das mit einer Funktion der Art:

for index = 1:100
array(index) = index;
end

blöderweise wird so das array in einer Zeile angelegt statt in einer Spalte, statt

1
2
3
4
...

habe ich also

1 2 3 4 5 ...

wie kann ich den code anpassen, daß das Array als Spalte geschrieben wird (muß leider sien, weil es nicht das einzige Array ist und alle anderen in Spaltenform vorliegen)?

Sephiroth
2009-10-08, 20:58:31
sicher das das nicht nur die ausgabe so ist? andernfalls transpose(A)

edit: http://en.wikibooks.org/wiki/MATLAB_Programming/Introduction_to_array_operations also doch nicht nur die ausgabe, naja ...

JFZ
2009-10-08, 21:13:38
sicher das das nicht nur die ausgabe so ist? andernfalls transpose(A)

edit: http://en.wikibooks.org/wiki/MATLAB_Programming/Introduction_to_array_operations also doch nicht nur die ausgabe, naja ...

ahh, transpose ist das Stichwort. Danke auf jeden Fall.

Jetzt wüsste ich nur noch gerne, wie bei solchen Operationen denn festgelegt wird, ob Arrays in Spalten oder in Zeilen geschrieben werden. Oder ist das Zufall :(

moloch
2009-10-08, 22:28:07
>> A=[1 2 3 4];
>> A

A =

1 2 3 4

>> B=A'

B =

1
2
3
4

>>

Spasstiger
2009-10-10, 12:01:56
Jetzt wüsste ich nur noch gerne, wie bei solchen Operationen denn festgelegt wird, ob Arrays in Spalten oder in Zeilen geschrieben werden. Oder ist das Zufall :(
Du selbst legst doch beim Erstellen des Vektors ("Array") fest, ob das ein Zeilen- oder Spaltenvektor sein soll.
Bei deinem Beispiel oben hast du auf die Initialisierung des Vektors verzichtet, was sich aber aus Performancegründen dringend empfiehlt. Matlab entscheidet sich in dem Fall für den Zeilenvektor
Beim folgenden Code wird automatisch ein Spaltenvektor generiert:

for index = 1:100
array(index,1) = index;
end

Wenn der Vektor array bereits als Zeilenvektor existiert, macht dir Matlab eine Matrix, in der die erste Spalte und die erste Zeile die Zahlen der Variable index enthalten.
Am Besten initialisiert du den Vektor array selbst:

array=zeros(100,1);
for index = 1:100
array(index) = index;
end

JFZ
2009-10-10, 20:21:52
Du selbst legst doch beim Erstellen des Vektors ("Array") fest, ob das ein Zeilen- oder Spaltenvektor sein soll.
Bei deinem Beispiel oben hast du auf die Initialisierung des Vektors verzichtet, was sich aber aus Performancegründen dringend empfiehlt. Matlab entscheidet sich in dem Fall für den Zeilenvektor
Beim folgenden Code wird automatisch ein Spaltenvektor generiert:

for index = 1:100
array(index,1) = index;
end

Wenn der Vektor array bereits als Zeilenvektor existiert, macht dir Matlab eine Matrix, in der die erste Spalte und die erste Zeile die Zahlen der Variable index enthalten.
Am Besten initialisiert du den Vektor array selbst:

array=zeros(100,1);
for index = 1:100
array(index) = index;
end


Wie mache ich die initialisierung, wenn ich eigentlich noch gar nicht weiß, wie lang das Array wird? Konkret ist es keine for-schleife womit das Array befüllt wird, sondern ein auslesen einer datei (quasi bis EndOfFile).

Spasstiger
2009-10-10, 21:29:46
Wie groß das Array bzw. besser gesagt der Vektor (was du verwendest, sind Vektoren, Arrays gibts in Matlab nur in Form von "cell arrays") wird, musst du halt ungefähr abschätzen. Das Problem ist, dass sich die Laufzeit um ein Vielfaches verlängert, wenn der Vektor mit jedem Schleifendurchlauf größer wird. Bei eine Millionen Schleifendurchläufen fällt das auf. ;)
Und Schleifen sind generell sehr lahm in Matlab. Nach Möglichkeit sollte man immer schauen, dass mein sein Problem vektoriell lösen kann. Vektoren verrechnen kann Matlab sehr flott, je nach Vektor- oder Matrixgröße kann aber viel Speicher erforderlich werden.

JFZ
2009-10-10, 23:22:47
Wie groß das Array bzw. besser gesagt der Vektor (was du verwendest, sind Vektoren, Arrays gibts in Matlab nur in Form von "cell arrays")
Hm, ja, ich verwende da blos ein eindimensionales Array. Würde auch einen vektor nehmen, falls Mathlab das unterscheiden würde.



Wie groß das Array [...] musst du halt ungefähr abschätzen. Das Problem ist, dass sich die Laufzeit um ein Vielfaches verlängert, wenn der Vektor mit jedem Schleifendurchlauf größer wird. Bei eine Millionen Schleifendurchläufen fällt das auf. ;)
Und Schleifen sind generell sehr lahm in Matlab.
Abschätzbar ist da leider nichts. Meßdatenverabreitung kann von 2 bis vielleicht 2000000 elementen gehen, je nachdem wie die Messung verlaufen ist :(

Wie groß das Array [...]
Und Schleifen sind generell sehr lahm in Matlab. Nach Möglichkeit sollte man immer schauen, dass mein sein Problem vektoriell lösen kann. Vektoren verrechnen kann Matlab sehr flott, je nach Vektor- oder Matrixgröße kann aber viel Speicher erforderlich werden.

Vielleicht kennst du ja eine andere Lösung für mein Problem:
ich habe ein Array "Werte" und ein zugehöriges Array "Zeitstempel". Nun will ich diese Werte auf eine neue, schon existierende Zeitachse bringen. Interpolation hatte ich mal versucht, allerdings ist "linear" untauglich, weil es sich um digitale Werte handelt und interpolierte Zwischenwerte das Ergebnis verfälschen würden. auch "nearest neighbor" passt leider nicht. Was ich bräuchte wäre sowas wie "left neighbor" (Würde alsoeiner Grafik mit Treppenstufen entsprechen, bei der ein Wert so lange gültig bleibt, bis ein neuer Wert registriert wird). Gibt es für so eine Umwandlung einen einfachen Ansatz?

Spasstiger
2009-10-10, 23:56:00
ich habe ein Array "Werte" und ein zugehöriges Array "Zeitstempel". Nun will ich diese Werte auf eine neue, schon existierende Zeitachse bringen.
Du willst also neu abtasten. Grundsätzlich geht man beim Abtasten auf digitale Werte folgendermaßen vor, wenn man sich kein verfälschendes Aliasing einhandeln möchte:
- Originalsignal auf die halbe Abtastfrequenz des neuen Signals tiefpassfiltern
- Mit der neuen Frequenz abtasten
- Werte quantisieren

Wenn du die Signal-Processing-Toolbox hast, kannst du ganz einfach einen Tiefpassfilter mit dem FDATool erstellen. Andernfalls kannst du immer noch den Befehl filter() verwenden und die Koeffizienten für den Tiefpassfilter selbst festlegen. Oder du holst dir aus dem Netz eine fertige Tiefpassfunktion. /EDIT: Das funktioniert allerdings nur, wenn die Abtastpunkte gleiche zeitliche Abstände haben.
Neu abtasten kannst du durchaus per Interpolation.
Und quantisieren ist einfach eine Schwellwertentscheidung.

Bei deiner Methode "left neighbor" willst du Werte generieren, auf die du aus deiner Messung gar nicht schließen kannst.

P.S.: Wenn in deinem "Array" nur Zahlen desselben Datentyps (Integer oder Float) stehen, ist ein Vektor die richtige Darstellungsform dafür in Matlab.

/EDIT: Seh ich das richtig, dass dein Messsignalvektor jedesmal dann einen neuen Wert bekommt, wenn sich der (quantisierte) Messwert ändert? Wenn ja, dann vergiss meine obigen Ausführungen. Da war ich zu sehr auf klassische Signalverarbeitung fixiert. Wenn du die genauen Zeitpunkte kennst, zu denen sich am Signal überhaupt was tut, dann kennst du das Signal ja quasi komplett. Deine "left neighbor"-Methode ist dann auch legitim. Ich überleg mir mal was.

/EDIT: Hier ein Code ohne Schleifen für dein Left-Neighbor-Problem:

clc; % Löscht Kommandofenster
clear all; % Löscht Objekte im Speicher

time_instants_old = [0,11,15,21,28,38,41,52,54,60,67,72] % gemessene Zeitpunkte
values_old = [0, 1, 4, 1,-3, 6, 2, 3, 6, 9, 1, 8] % gemessene Werte
time_instants_new = [0,10,20,30,40,50,60,70,80] % Zeitpunkte der neuen Zeitachse

A = [time_instants_old time_instants_old(end)*ones(1,length(time_instants_new)-1)]';
A_values = [values_old values_old(end)*ones(1,length(values_old)-1)]';
B = toeplitz(A,zeros(size(time_instants_new)));
B_values = toeplitz(A_values,zeros(size(time_instants_new)));
C = (time_instants_new'*ones(1,length(time_instants_old)+length(time_instants_new)-1))';
D = C-B;
D(D<0) = inf;
[E,ind] = min(D);

values_new = diag(B_values(ind,1:length(ind)))' % Werte auf der neuen Zeitachse
corresponding_time_instants_old = diag(B(ind,1:length(ind)))' % korrespondierende Zeitpunkte der alten Zeitachse

Ein- und Ausgabe erfolgen als Zeilenvektoren. Wenn du das ' bei den letzten zwei Zeilen wegnimmst, hast du deine gewünschten Spaltenvektoren.
Das ist die Ausgabe bei meinem obigen Codebeispiel:

time_instants_old =
0 11 15 21 28 38 41 52 54 60 67 72
values_old =
0 1 4 1 -3 6 2 3 6 9 1 8
time_instants_new =
0 10 20 30 40 50 60 70 80
values_new =
0 0 4 -3 6 2 9 1 8
corresponding_time_instants_old =
0 0 15 28 38 41 60 67 72

Wenn die neue Zeitachse stets konstante Abstände zwischen den Zeitpunkten hat, könnte man das Problem auch deutlich einfacher lösen.
Übrigens: Mein Code-Beispiel oben geht leider sehr verschwenderisch mit dem Speicher um, so dass sich eine simple Schleifenlösung letztlich doch als schneller herausstellen könnte.

JFZ
2009-10-11, 10:29:26
P.S.: Wenn in deinem "Array" nur Zahlen desselben Datentyps (Integer oder Float) stehen, ist ein Vektor die richtige Darstellungsform dafür in Matlab.

wären alles float. Gibt es unter Matlab eine Unterschiedung zwischen Array und Vektor?




/EDIT: Seh ich das richtig, dass dein Messsignalvektor jedesmal dann einen neuen Wert bekommt, wenn sich der (quantisierte) Messwert ändert?

Für einen Teil der Messsignalvektoren die ich verwende gibt es nur genau dann einen neuen Wert, wenn sich der Messwert ändert.
Für die restlichen Messsignalvektoren gibt es zwar immer einen neuen Wert, wenn sich der Messwert ändert, allerdings kann ein un der selbe Wert mehrfach hintereinander vorkommen (die signalquelle rechnet in einem definiertem Zeitraster, so daß keine Zwischenwerte möglich sind).




/EDIT: Hier ein Code ohne Schleifen für dein Left-Neighbor-Problem:

clc; % Löscht Kommandofenster
clear all; % Löscht Objekte im Speicher

time_instants_old = [0,11,15,21,28,38,41,52,54,60,67,72] % gemessene Zeitpunkte
values_old = [0, 1, 4, 1,-3, 6, 2, 3, 6, 9, 1, 8] % gemessene Werte
time_instants_new = [0,10,20,30,40,50,60,70,80] % Zeitpunkte der neuen Zeitachse

A = [time_instants_old time_instants_old(end)*ones(1,length(time_instants_new)-1)]';
A_values = [values_old values_old(end)*ones(1,length(values_old)-1)]';
B = toeplitz(A,zeros(size(time_instants_new)));
B_values = toeplitz(A_values,zeros(size(time_instants_new)));
C = (time_instants_new'*ones(1,length(time_instants_old)+length(time_instants_new)-1))';
D = C-B;
D(D<0) = inf;
[E,ind] = min(D);

values_new = diag(B_values(ind,1:length(ind)))' % Werte auf der neuen Zeitachse
corresponding_time_instants_old = diag(B(ind,1:length(ind)))' % korrespondierende Zeitpunkte der alten Zeitachse

Ein- und Ausgabe erfolgen als Zeilenvektoren. Wenn du das ' bei den letzten zwei Zeilen wegnimmst, hast du deine gewünschten Spaltenvektoren.
Das ist die Ausgabe bei meinem obigen Codebeispiel:

time_instants_old =
0 11 15 21 28 38 41 52 54 60 67 72
values_old =
0 1 4 1 -3 6 2 3 6 9 1 8
time_instants_new =
0 10 20 30 40 50 60 70 80
values_new =
0 0 4 -3 6 2 9 1 8
corresponding_time_instants_old =
0 0 15 28 38 41 60 67 72


muß ich mal ausprobieren. Glaub, ich muß mir mal die Ausgaben der zwischenwerte (A, B, C, D) mal anschauen um das Beispiel zu verstehen (matlab hab ich erst wieder am Montag)



Wenn die neue Zeitachse stets konstante Abstände zwischen den Zeitpunkten hat, könnte man das Problem auch deutlich einfacher lösen.

momentan ist das sogar der Fall. Muß aber prüfen, ob das immer so wäre.

so hätte ich es mir bisher vorgestellt (leider nicht direkt vektoriell):
ist das ' tatsächlich ein gülter Matlab-befehl?

for k = 1:length(neueZeitskala)
for i = 1: length(messdaten)
if neueZeitskala(k) >= alteZeitskala(i)
neueDaten'(k) = messdaten(i);
end
end
end

Spasstiger
2009-10-11, 12:22:59
wären alles float. Gibt es unter Matlab eine Unterschiedung zwischen Array und Vektor?
Arrays sind in Matlab Cell Arrays. In Cell Arrays können auch andere Datentypen als Zahlen stehen, auf die Einträge wird anders zugegriffen als bei Vektoren. Vektoren enthalten Zahlen (reell, imaginär, komplex). Für Vektoren gilt alles, was auch in der Vektorrechnung gilt. Matlab hat viele Vektorbefehle, die man aus klassischen Programmiersprachen in Zusammenhang mit Arrays nicht kennt. Deshalb finde ich es wichtig, sich mit dem Konzept der Vektoren (und Matrizen) vertraut zu machen. Du sprichst ja auch nicht von einem Messarray, sondern von einem Messvektor. Auch lassen sich Algorithmen in vektorieller Notation mit Matlab leicht und effizient implementieren.

muß ich mal ausprobieren.
Aber Vorsicht, lass erstmal keine Messsignale mit mehr als 100.000 Einträgen drüberlaufen, sonst ist Matlab heftig am Auslagern, wenn du nicht extrem viel RAM hast (zumindest die 64-Bit-Version, die 32-Bit-Version meldet wahrscheinlich "Out of memory"). Ich hab meinen Code leider mit sehr viel Redundanz umgesetzt, um auf Schleifen verzichten zu können. Aber in dem Fall hier scheinen Schleifen doch sinnvoller zu sein, weil das Problem sonst einfach zu viel Speicher belegt. Wenn man kürzere Messvektoren hat und die Schleifen sehr häufig durchläuft, macht eine vektorielle Implementierung mehr Sinn.

so hätte ich es mir bisher vorgestellt (leider nicht direkt vektoriell):
ist das ' tatsächlich ein gülter Matlab-befehl?
[...]
' ist ein gültiger Matlab-Befehl und bewirkt dasselbe wir transpose(). Allerdings darf ' nur rechts vom Gleichheitszeichen stehen. Schreibe einfach nach der Schleife eine Zeile neueDaten=neueDaten'.
Deine Code liefert übrigens nach dieser Korrektur die gleiche Ausgabe wie mein Code. Noch ein Tipp: Dein Vektor neueDaten ist immer so lang wie dein Vektor neueZeitskala. Also mach vorher noch eine entsprechende Initialisierung des Vektors neueDaten. Hier mal dein Code mit der Korrektur und dem Optimierungsvorschlag:

neueDaten = zeros(size(neueZeitskala));
for k = 1:length(neueZeitskala)
for i = 1: length(messdaten)
if neueZeitskala(k) >= alteZeitskala(i)
neueDaten(k) = messdaten(i);
end
end
end
neueDaten=neueDaten'
Wenn neueZeitskala als Spaltenvektor vorliegt, lässt du die letzte Zeile einfach weg.

JFZ
2009-10-11, 12:58:16
Arrays sind in Matlab Cell Arrays. In Cell Arrays können auch andere Datentypen als Zahlen stehen, auf die Einträge wird anders zugegriffen als bei Vektoren. Vektoren enthalten Zahlen (reell, imaginär, komplex). Für Vektoren gilt alles, was auch in der Vektorrechnung gilt. Matlab hat viele Vektorbefehle, die man aus klassischen Programmiersprachen in Zusammenhang mit Arrays nicht kennt. Deshalb finde ich es wichtig, sich mit dem Konzept der Vektoren (und Matrizen) vertraut zu machen. Du sprichst ja auch nicht von einem Messarray, sondern von einem Messvektor. Auch lassen sich Algorithmen in vektorieller Notation mit Matlab leicht und effizient implementieren.

hmm.. muß ich separat in Matlab dann sagen, daß "neueDaten" ein Vektor sein soll? Oder mact Matlab selbstständig die Unterscheidung zwischen CellArray und Vektor?


' ist ein gültiger Matlab-Befehl und bewirkt dasselbe wir transpose(). Allerdings darf ' nur rechts vom Gleichheitszeichen stehen. Schreibe einfach nach der Schleife eine Zeile neueDaten=neueDaten'.
Deine Code liefert übrigens nach dieser Korrektur die gleiche Ausgabe wie mein Code. Noch ein Tipp: Dein Vektor neueDaten ist immer so lang wie dein Vektor neueZeitskala. Also mach vorher noch eine entsprechende Initialisierung des Vektors neueDaten. Hier mal dein Code mit der Korrektur und dem Optimierungsvorschlag:

neueDaten = zeros(size(neueZeitskala));
for k = 1:length(neueZeitskala)
for i = 1: length(messdaten)
if neueZeitskala(k) >= alteZeitskala(i)
neueDaten(k) = messdaten(i);
end
end
end
neueDaten=neueDaten'
Wenn neueZeitskala als Spaltenvektor vorliegt, lässt du die letzte Zeile einfach weg.


danke schön.
da "neueZeitskala" schon ein spaltenvektor ist wird durch die Verwendung von size() auch "neueDaten" gleich als spaltenvektor initialisiert, oder?

Spasstiger
2009-10-11, 13:10:35
Oder mact Matlab selbstständig die Unterscheidung zwischen CellArray und Vektor?
Es kommt immer drauf an, wie du die Daten holst. Wenn nur Zahlen des gleichen Datentyps drinstehen, ist es automatisch ein Vektor. Und ein Befehl A = [1,2,3,4] legt auch immer einen Vektor an. Beim Lesen von Textdateien mit Strings legt Matlab ein Cell Array an.

da "neueZeitskala" schon ein spaltenvektor ist wird durch die Verwendung von size() auch "neueDaten" gleich als spaltenvektor initialisiert, oder?
Genau. Du kannst auch einfach schreiben:
neueDaten = neueZeitskala
Aber das verwirrt evtl. Jemanden, der den Code verstehen möchte. Deshalb initialisiere ich persönlich lieber mit Nullen.

JFZ
2009-10-11, 17:05:06
kann ich eigentlich, wenn
"if neueZeitskala(k) >= alteZeitskala(i) "

nicht mehr erfüllt ist (also der else-zweig) irgendwie aus den beiden Schleifen springen ohne das gesamte Programm zu unterbrechen?
wäre ja eine Laufzeitoptimierung...

Spasstiger
2009-10-11, 17:15:52
Mit break springst du aus der aktuellen Schleife. Wenn du aus weiteren Schleifen springen möchtest, musst du eine entsprechende Variable (z.B. breakLoops) setzen und diese in den äußeren Schleifen abfragen.
Sauberer Stil ist die Verwendung von 'break' aber nicht, da es einem Goto entspricht. Besser wäre es, eine while-Schleife zu verwenden, in der hochgezählt wird und ausgeführt wird, solange keine der beiden Abbruchbedingungen erfüllt ist (neueZeitskala(k) >= alteZeitskala(i) oder letztes Element erreicht).

Pinoccio
2009-10-11, 19:38:41
clc; % Löscht Kommandofenster
clear all; % Löscht Objekte im Speicher

time_instants_old = [0,11,15,21,28,38,41,52,54,60,67,72] % gemessene Zeitpunkte
values_old = [0, 1, 4, 1,-3, 6, 2, 3, 6, 9, 1, 8] % gemessene Werte
time_instants_new = [0,10,20,30,40,50,60,70,80] % Zeitpunkte der neuen Zeitachse

A = [time_instants_old time_instants_old(end)*ones(1,length(time_instants_new)-1)]';
A_values = [values_old values_old(end)*ones(1,length(values_old)-1)]';
B = toeplitz(A,zeros(size(time_instants_new)));
B_values = toeplitz(A_values,zeros(size(time_instants_new)));
C = (time_instants_new'*ones(1,length(time_instants_old)+length(time_instants_new)-1))';
D = C-B;
D(D<0) = inf;
[E,ind] = min(D);

values_new = diag(B_values(ind,1:length(ind)))' % Werte auf der neuen Zeitachse
corresponding_time_instants_old = diag(B(ind,1:length(ind)))' % korrespondierende Zeitpunkte der alten Zeitachse

Ein- und Ausgabe erfolgen als Zeilenvektoren. Wenn du das ' bei den letzten zwei Zeilen wegnimmst, hast du deine gewünschten Spaltenvektoren.
Das ist die Ausgabe bei meinem obigen Codebeispiel:

time_instants_old =
0 11 15 21 28 38 41 52 54 60 67 72
values_old =
0 1 4 1 -3 6 2 3 6 9 1 8
time_instants_new =
0 10 20 30 40 50 60 70 80
values_new =
0 0 4 -3 6 2 9 1 8
corresponding_time_instants_old =
0 0 15 28 38 41 60 67 72Der geht aber schief, wenn deine Abschnitt, wo nichts neues kommt, größer ist als dein neuer Zeitschritt.
Dein Datenbeispiel deckt diesen Fall nicht ab.

mfg

Spasstiger
2009-10-11, 20:53:52
Ok, ich hab nicht wirklich drauf geachtet, alle Fälle abzudecken. Aber ich wollt ja auch nur sehen, ob man das Problem prinzipiell vektorisieren kann. Alles in allem rate ich von meiner Lösung ab, weil der Speicherbedarf zu groß ist. Mehrere 100.000x100.000-Matrizen sind halt einfach nicht mehr handlich.

Pinoccio
2009-10-11, 23:12:24
Aber ich wollt ja auch nur sehen, ob man das Problem prinzipiell vektorisieren kann.Die Verwendung eine Matrix macht aus diesem prinzipiell O(n)-Problem eines mit O(n^2). :ugly:

Vektorisieren (im MATLAB-Sinne) geht natürlich auch, da du aber Fallunterscheidungen machen musst, wird es mit Schleifen besser und vermutlich auch schneller gehen.
Außerdem würde mir kein Problem einfallen, was man nicht mit vielen Tricks und möglicherweise - so wie hier - äußerst ineffizient vektorisieren könnte.

a) Optimierte for-Schleife mit bösem break:
temp1=1;
neueDaten = zeros(size(neueZeitskala));
for k = 1:length(neueZeitskala)
for i = temp1:length(messdaten)
if neueZeitskala(k) >= alteZeitskala(i)
pneueDaten(k) = messdaten(i);
temp1=i;
break
end
end
end

~ O(n)

b) while:
for k = 1:length(neueZeitskala)
neueDaten(k)=messdaten(i);
while ( neueZeitskala(k) < alteZeitskala(i) )
i=i+1;
end
end

ebenfalls ~ O(n).
Je größer die nicht-äqudistanten Schritte im Vergleich zu den äquidistanten werden, umso mehr schneller als a). Wenn, wie in Spasstigers Beispiel, das Verhältnis bei 1,4 liegt, dann bei mir rund 6-mal so schnell.

Mein Rechner steigt - RAM-Mangel-bedingt - bei rund 20 Mio. Samples aus. Zeit fürs Resampling: 1 Sekunde ;-)

/edit: Ein Blick auf die Uhr bestätigt, was fefe (http://blog.fefe.de/?ts=b42f3bc8) schreibt:
Heute zeige ich euch mal, wie sich ein Hacker einen perfekten Sonntag[abend] vorstellt. [Ich habe mich] hingesetzt und wollten diesen Code hier optimieren.


mfg