WICHTIG: Der Betrieb von goMatlab.de wird privat finanziert fortgesetzt. - Mehr Infos...

Mein MATLAB Forum - goMatlab.de

Mein MATLAB Forum

 
Gast > Registrieren       Autologin?   

Partner:




Forum
      Option
[Erweitert]
  • Diese Seite per Mail weiterempfehlen
     


Gehe zu:  
Neues Thema eröffnen Neue Antwort erstellen

Finde den Fehler!

 

Lloyd Blankfein
Forum-Century

Forum-Century



Beiträge: 149
Anmeldedatum: 23.02.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 03.05.2012, 11:46     Titel: Finde den Fehler!
  Antworten mit Zitat      
Hallo,

ich habe diese Funktion zwecks Verbesserung der Performance neugeschrieben:

Code:

        function CalcPeriodAll_OLD(obj)
            obj.PeriodAll=obj.ts(:,1);%Date column
            obj.PeriodAll=[obj.PeriodAll,zeros(size(obj.PeriodAll,1),1)];%Expand the matrix
            for i=1:size(obj.PeriodAll,1)
                tmpDate=obj.PeriodAll(i,1)+1;
                if weekday(tmpDate)==7%Saturday
                    tmpDate=tmpDate+2;%Saturday->monday
                elseif weekday(tmpDate)==1%Sunday
                    tmpDate=tmpDate+1;%Sunday->monday
                end
                for m=1:size(obj.Holidays,1)
                    if obj.Holidays(m)>tmpDate
                        break;%Exit loop
                    end
                    if tmpDate==obj.Holidays(m)
                        tmpDate=tmpDate+1;
                        if weekday(tmpDate)==7%Saturday
                            tmpDate=tmpDate+2;%Saturday->monday
                        elseif weekday(tmpDate)==1%Sunday
                            tmpDate=tmpDate+1;%Sunday->monday
                        end
                    end
                end
                [~, tmpMonth, ~, ~, ~, ~] = datevec(tmpDate);
                [~, ~, tmpDay, ~, ~, ~] = datevec(tmpDate);
                if tmpDay<16
                    obj.PeriodAll(i,2)=tmpMonth*2-1;
                else
                    obj.PeriodAll(i,2)=tmpMonth*2;
                end  
            end
        end
 


Code:

        function CalcPeriodAll(obj)
            obj.PeriodAll=[obj.ts(:,1),zeros(size(obj.ts,1),1)];%Inline: %Date column and expand matrix
            for i=1:size(obj.PeriodAll,1)
                tmpDate=obj.PeriodAll(i,1)+1;
                if weekday(tmpDate)==7%Saturday
                    tmpDate=tmpDate+2;%Saturday->monday
                elseif weekday(tmpDate)==1%Sunday
                    tmpDate=tmpDate+1;%Sunday->monday
                end
                [tf,~]=ismember(tmpDate,obj.Holidays);
                if tf
                    tmpDate=tmpDate+1;
                    if weekday(tmpDate)==7%Saturday
                        tmpDate=tmpDate+2;%Saturday->monday
                    elseif weekday(tmpDate)==1%Sunday
                        tmpDate=tmpDate+1;%Sunday->monday
                    end
                end
                [~, tmpMonth, tmpDay, ~, ~, ~] = datevec(tmpDate);
                if tmpDay<16
                    obj.PeriodAll(i,2)=tmpMonth*2-1;
                else
                    obj.PeriodAll(i,2)=tmpMonth*2;
                end  
            end
        end
 


Die Funktionen liefern nun unterschiedliche Ergebnisse PeriodAll. Ich finde den Fehler nicht!!! Könnt ihr mir helfen?

Vielen Dank!
Lloyd
Private Nachricht senden Benutzer-Profile anzeigen


Sirius3
Forum-Guru

Forum-Guru


Beiträge: 441
Anmeldedatum: 11.11.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 04.05.2012, 16:31     Titel:
  Antworten mit Zitat      
Hallo LLoyd,

im ersten Fall läuft die Schleife nach gefundenem Feiertag weiter.
Zum Beispiel Karfreitag wird Samstag, wird Ostermontag, wird Dienstag.
Inklusive eines etwas eleganteren Wochenend-Tests sähe das dann so aus:
Code:

WEEKENDSHIFT=[1,0,0,0,0,0,2]; % Samstag+Sonntag -> Montag
HOLYSHIFT=[1,1,1,1,1,3,2]; % mit Feiertag: ein Tag weiter, auszer Freitag+Samstag -> Montag
  [...]
  tmpDate=tmpDate+WEEKENDSHIFT(weekday(tmpDate));
  while ismember(tmpDate,obj.Holidays)
    tmpDate=tmpDate+HOLYSHIFT(weekday(tmpDate));
  end;
  [...]
 


Grüße
Sirius
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 04.05.2012, 17:09     Titel: Re: Finde den Fehler!
  Antworten mit Zitat      
Hallo Lloyd Blankfein,

Das wiederholte Aufrufen von WEEKDAY() kostet viel Zeit. Da dies nur eine Modulo(7) Berechnung ist, könntest Du das auch inline berechnen.

Statt
Code:
[~, tmpMonth, ~, ~, ~, ~] = datevec(tmpDate);
                [~, ~, tmpDay, ~, ~, ~] = datevec(tmpDate);

wäre dies wohl etwa doppelt so schnell:
Code:
[~, tmpMonth, tmpDay, ~, ~, ~] = datevec(tmpDate);


Es ist deutlich effizienter in ein DOUBLE Array zu schreiben, statt in ein Feld eines Structs.
Code:

tmp = zeros(size(obj.PeriodAll, 1), 1);
...
tmp(i) = tmpMonth*2-1;
...
% Und zum Schluß:
obj.PeriodAll(:,2) = tmp;

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Lloyd Blankfein
Themenstarter

Forum-Century

Forum-Century



Beiträge: 149
Anmeldedatum: 23.02.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 09.05.2012, 09:12     Titel:
  Antworten mit Zitat      
Hallo ihr beiden,

vielen Dank für eure Tipps:

Code:

        function CalcPeriodAll(obj)
            obj.PeriodAll=obj.ts(:,1);%Date column
            tmp = zeros(size(obj.PeriodAll, 1), 1);
            WEEKENDSHIFT=[1,0,0,0,0,0,2]; % Saturday+Sunday -> Monday
            HOLYSHIFT=[1,1,1,1,1,3,2]; % with Holyday: go one day further, exeption: Friday+Saturday -> Monday
            for i=1:size(obj.PeriodAll,1)
                tmpDate=obj.PeriodAll(i,1)+1+WEEKENDSHIFT(weekday(obj.PeriodAll(i,1)+1));
                while ismember(tmpDate,obj.Holidays)
                    tmpDate=tmpDate+HOLYSHIFT(weekday(tmpDate));
                end;
                [~, tmpMonth, tmpDay, ~, ~, ~] = datevec(tmpDate);
                if tmpDay<16
                    tmp(i) = tmpMonth*2-1;
                else
                    tmp(i) = tmpMonth*2;
                end  
            end
            obj.PeriodAll(:,2) = tmp;      
        end
 


Immerhin läuft die Funktion jetzt um den Faktor 2 schneller.

@Jan:
Zitat:
Es ist deutlich effizienter in ein DOUBLE Array zu schreiben, statt in ein Feld eines Structs.


Wie meinst du das? Bei PeriodAll handelt es sich um einen nx2-double-Array.

Gruß,
Lloyd
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 09.05.2012, 10:50     Titel:
  Antworten mit Zitat      
Hallo Lloyd Blankfein,

Wenn "tmpDate" ein Skalar ist, wäre
Code:

schneller als
Code:


Zitat:
Wie meinst du das? Bei PeriodAll handelt es sich um einen nx2-double-Array.

Nein. Die Variable "PeriodAll" existiert gar nicht. Bisher existiert nur "obj.PeriodAll". Intern muss dies geschehen, um die Werte zu ändern:
1. Suche "obj" in der Variablen-Tabelle.
2. Finde den Pointer zur Liste der Feld-Namen.
3. Durchsuche die Feld-Namen Liste mit STRCMP bis das Feld "PeriodAll" gefunden wird.
4. Find den Pointer zu den dazugehörigen Feld.
5. Finde den Pointer zu den Daten des Feldes, also zum eigentliche Inhalt von "obj.PeriodAll".

Wenn man dagegen ein Double-Array verwendet, das nicht in einem Struct verschachtelt ist, merkt sich die JIT-Acceleration den Pointer zu den Daten direkt und die ganzen Suchereien entfallen. Deshalb ist es im Allgemeinen effizienter, ein temporäres Array zu verwenden, wenn ein Struct-Feld in einer Schleife häufig verändert wird.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Lloyd Blankfein
Themenstarter

Forum-Century

Forum-Century



Beiträge: 149
Anmeldedatum: 23.02.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 09.05.2012, 11:23     Titel:
  Antworten mit Zitat      
Zitat:

Nein. Die Variable "PeriodAll" existiert gar nicht. Bisher existiert nur "obj.PeriodAll". Intern muss dies geschehen, um die Werte zu ändern:
1. Suche "obj" in der Variablen-Tabelle.
2. Finde den Pointer zur Liste der Feld-Namen.
3. Durchsuche die Feld-Namen Liste mit STRCMP bis das Feld "PeriodAll" gefunden wird.
4. Find den Pointer zu den dazugehörigen Feld.
5. Finde den Pointer zu den Daten des Feldes, also zum eigentliche Inhalt von "obj.PeriodAll".

Wenn man dagegen ein Double-Array verwendet, das nicht in einem Struct verschachtelt ist, merkt sich die JIT-Acceleration den Pointer zu den Daten direkt und die ganzen Suchereien entfallen. Deshalb ist es im Allgemeinen effizienter, ein temporäres Array zu verwenden, wenn ein Struct-Feld in einer Schleife häufig verändert wird.


Oh, ... na das muss man auch erstmal wissen!

Wenn ich jetzt z.B. die Werte von obj.PeriodAll(:,2) ändern möchte, werden tatsächlich die Schritte 1.-5. mit jeder Iteration durchgenudelt? "Merkt" sich Matlab nicht die Adresse von obj.PeriodAll bevor die for-Schleife durchlaufen wird?

Gruß,
Lloyd
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 13.05.2012, 01:32     Titel:
  Antworten mit Zitat      
Hallo Lloyd Blankfein,

Zitat:
Oh, ... na das muss man auch erstmal wissen!

Stimmt. Um Matlab wirklich effizient benutzen zu können, muss man zunächst wissen, wie der Code intern abgearbeitet wird. Dies steht allerdings nicht in der Dokumentation. Aber im Grunde unterscheiden sich Compiler nicht wesentlich, so dass eine Vorlesung Compiler-Bau und Erfahrung mit z.B. C-Compilern bereits einen tieferen Einblick erlauben.

Zitat:
Wenn ich jetzt z.B. die Werte von obj.PeriodAll(:,2) ändern möchte, werden tatsächlich die Schritte 1.-5. mit jeder Iteration durchgenudelt? "Merkt" sich Matlab nicht die Adresse von obj.PeriodAll bevor die for-Schleife durchlaufen wird?

Die JIT-Beschleunigung kann inzwischen einige Tricks. Ob Matlab ausnutzen kann, dass "obj.PeriodAll" ein statischer Pointer zu einem DOUBLE-Array ist, oder eben nicht, kannst Du am besten selbst ausprobieren. Setze ein TIC/TOC um den Code, lasse ihn am besten noch mehrfach durchlaufen, und schaue, was schneller ist.

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Lloyd Blankfein
Themenstarter

Forum-Century

Forum-Century



Beiträge: 149
Anmeldedatum: 23.02.11
Wohnort: ---
Version: ---
     Beitrag Verfasst am: 23.05.2012, 17:14     Titel:
  Antworten mit Zitat      
Hallo,

inzwischen sieht meine Funktion so aus:

Code:

        function CalcPeriodAll(obj)
            obj.PeriodAll=obj.ts(:,1);%Date column
            tmp = zeros(size(obj.PeriodAll, 1), 1);
            WEEKENDSHIFT=[1,0,0,0,0,0,2]; % Saturday+Sunday -> Monday
            HOLYSHIFT=[1,1,1,1,1,3,2]; % with Holyday: go one day further, exeption: Friday+Saturday -> Monday
            for i=1:size(obj.PeriodAll,1)
                tmpDate=obj.PeriodAll(i,1)+1+WEEKENDSHIFT(mod(fix(obj.PeriodAll(i,1)+1)-2,7)+1);
                while any(tmpDate == obj.Holidays) %33.6% der Laufzeit
                    tmpDate=tmpDate+HOLYSHIFT(mod(fix(tmpDate)-2,7)+1);
                end;
                [~, tmpMonth, tmpDay, ~, ~, ~] = datevecmx(tmpDate);%36.3% der Laufzeit
                if tmpDay<16
                    tmp(i) = tmpMonth*2-1;
                else
                    tmp(i) = tmpMonth*2;
                end
            end
            obj.PeriodAll(:,2) = tmp;      
        end
 


weekday wurde durch mod(fix(tmpDate)-2,7)+1 ersetzt
datevec wurde durch datevecmx ersetzt

Trotzdem möchte ich den Code weiter beschleunigen. Hat jemand eine Idee?

Vielen Dank für eure Hilfe!
Gruß, Lloyd
Private Nachricht senden Benutzer-Profile anzeigen
 
Jan S
Moderator

Moderator


Beiträge: 11.057
Anmeldedatum: 08.07.10
Wohnort: Heidelberg
Version: 2009a, 2016b
     Beitrag Verfasst am: 23.05.2012, 17:38     Titel:
  Antworten mit Zitat      
Hallo Lloyd Blankfein,

Ich sage nichts mehr über die Zeit, die beim Referenzieren von Struct-Feldern und mehrdimensionalen Arrays verloren geht.

Hier noch eine Methode, über die ich mir noch nicht den Mund fuselig geredet habe:
Code:
tmp(i) = tmpMonth*2- (tmpDay<16);

Gruß, Jan
Private Nachricht senden Benutzer-Profile anzeigen
 
Neues Thema eröffnen Neue Antwort erstellen



Einstellungen und Berechtigungen
Beiträge der letzten Zeit anzeigen:

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
.





 Impressum  | Nutzungsbedingungen  | Datenschutz | FAQ | goMatlab RSS Button RSS

Hosted by:


Copyright © 2007 - 2025 goMatlab.de | Dies ist keine offizielle Website der Firma The Mathworks

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.