Verfasst am: 31.10.2008, 12:37
Titel: Initialisierung von struct-arrays
Hallo
ich möchte gerne eine Struktur folgender Form haben:
Test(:).x(:,:)
Test(:).y(:,:)
Das ganze soll vorher mit 0 Initialisiert werden, weil es ja von Matlab heißt, dass ein Aufbauen eines Arrays in einer Schleife zu lange dauert und man das vorher schonmal initialisiert haben soll.
Aber wie soll ich das ohne eine for-Schleife machen.
Mein Idee geht nur mit for-Schleife:
for q = 1 : 10
Test(q).x = zeros(5,4);
Test(q).y = zeros(5,4);
end
dann hat man sofort einen 1x13 struct array mit Nullen in allen Feldern.
Was ist aber, wenn ich nicht 13, sonder 1300 structs haben will?
Dann muss es doch irgendwie anders gehen, als die Zeile mit 1300 Nullen {0 0 0 ....} zu schreiben?
.... Naja, beim Schreiben auch schon die Lösung gefunden:
Damit könnte man nun ein Struct-Array initialisieren. Allerdings erzeugt dies nicht 1000 Matrizen, wie es für eine ordentliche Pre-allocierung ja notwendig wäre, sondern nur eine! Das Cell-Array "c" wird mit sogenannten Shared-Data-Copies gefüllte, also Variablen, die alle auf den gleichen Speicherbereich zeigen. Das ist auf Anhieb erst mal viel schneller und der Speicherbedarf ist deutlich kleiner. Aber sowie man die Werte ändert, ist zusätzlicher Aufwand nötig, um die Shared-Data-Copy per "Deep-Copying" in ein eigenständiges Array zu verwandeln. Dazu müssen Einträge in den Listen der Referenzen geändert werden, was zusätzliche Zeit beansprucht. Deswegen ist "c(:) = {zeros(10, 20)}" im Gegensatz zum ersten Anschein keine Pre-allocierung (oder wie sich dieses Wort auf Deutsch schreiben mag).
Verblüffend, oder? Und wie findet man das heraus?
Code:
format debug % Nicht dokumentiert! Zeigt Meta-Infos an
c = cell(1, 2);
c(:) = {zeros(5, 4)};
c{1}
>> Structure address = 7d97028
m = 10
n = 20
pr = 341e5d50
pi = 0 % ... und dann die vielen Nullen
c{2}
>> Structure address = 7d97028
m = 10
n = 20
pr = 341e5d50
pi = 0 % ...
Wichtig sind hier die identischen "pr" Werte: Dies ist der Pointer zu den reellen Nutzdaten (pi ist 0, da keine imaginären Werte vorliegen). Beide Cell-Elemente verwenden also den gleichen Speicherbereich und das wird bei der Konstruktion des Structs auch weitergegeben. Sowie man dann schreibend darauf zugreift, werden die Daten zuerst dupliziert, was aber leider teuer ist.
Eine "richtige" Pre-allocation ist daher leider nur mit einer Schleife möglich:
Das ist meines Wissens nach tatsächlich der effizienteste Weg, die Arrays tatsächlich zu reservieren.
Besonders schnell ist das natürlich nicht, aber das liegt daran, dass hier eine ungeschickte Daten-Representation gewählt wurde. Ein einzelnes 3D-Array "zeros(5, 4, 10)" wäre deutlich schneller, aber man hätte nicht mehr die hübsche Aufteilung in ein Struct-Array.
Noch eine Bemerkung: Die explizite Verwendung von "ans" ist tückisch, weil es z.B. beim Debuggen zu anderen Ergebnissen führen kann. "ans" ist sehr "volatil" und man kann ein Überschreiben nicht garantiert verhindern. Also besser eine konkrete Variable verwenden:
Code:
c = cell(1, 13); % Tippfehler: Nicht "(1x13)"
c(:)={0}; %füllt es mit Nullen
"ans" enthält die letzte nicht in einer Variablen gespeicherte Rückgabe einer Funktion. Ich würde mich nicht darauf verlassen, dass z.B. ein TIMER Callback nicht unerwartet zwischen zwei Zeilen diese Variable überschreiben kann. Das wäre zwar ein exotischer Fall, aber falls er einträte kaum per Debugger zu finden, da er nicht reproduzierbar ist.
Das ist dann wie Autofahren ohne Sicherheitsgurt: In 99.99% aller Fälle passiert nix.
Der gezeigte Code pre-allociert das skalare Struct einwandfrei.
Man muss hier nun unterscheiden, ob das Struct-Array selbst pre-allociert wird, also alle Felder und die entgültige Größe definiert wird, oder aber die Arrays, die in den Feldern stehen! Das ist ein Unterschied.
Gruß, Jan
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.