SCL und Zykluszeitproblem

A

Anonymous

Guest
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

habe ein Problem mit der Zykluszeit bei folgendem Code:

Code:
FOR i:=1  TO DINT_TO_INT(TRUNC(n)) DO
  v:= v + x ** n;
  s:= s + v * a;
END_FOR;

Ich habe sechs dieser For-Schleifen in einem Baustein und die scheinen die Zykluszeit nach unten zu reißen. (ca. 120ms)
Zum testen hab ich mal drei der Schleifen auskommentiert, wobei die Zykluszeit sich dann um die Hälfte verringert.
Ich kann mir nicht vorstellen, das diese Anweisung die Laufzeit so stark beeinfußt?

Lässt sich diese Anweisung irgendwie optimieren, abgesehen von dem "DINT_TO_INT(TRUNC...)"

Fast vergessen: n ist ca. 50 :roll:

mfg
marco
 
Könnte schon sein das die Schleifen mächtig auf Zykluszeit gehen. Hast ja selbst schon denn Beweis erbracht. Um die hohe Zykluszeit zu umgehen wäre denkbar die Berechnungen aufzuteilen und nur bei Bedarf zu durchlaufen.

Gruß
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Marco,

Das Potenzieren benötigt schon deutlich Ausführungszeit, aber das ist wohl nicht zu umgehen. Ich würde jedoch DINT_TO_INT(TRUNC(n)) ersetzen, wobei der Zeitgewinn gegenüber dem Potenzieren eigentlich vernachlässigt werden kann.

Code:
m := DINT_TO_INT(TRUNC(n));

FOR i:=1  TO m DO 
  v:= v + x ** n; 
  s:= s + v * a; 
END_FOR;

Gruß, Onkel
 
Onkel Dagobert schrieb:
Code:
m := DINT_TO_INT(TRUNC(n));

FOR i:=1  TO m DO 
  v:= v + x ** n; 
  s:= s + v * a; 
END_FOR;

Gruß, Onkel
Ich würde beim Rechengang ansetzen:
n läuft von 1 bis m. Wenn du eine zusätzliche variable p einführst und schreibst:

p:=1;
FOR i:=1 TO m DO
p:=p*x;
v:= v + p;
s:= s + v * a;
END_FOR;
Ist P im 1. Durchlauf p=x =x**1;
im 2. Durchlauf p=x*x =x**2;
usw.
und du kannst das potenzieren ganz sparen.
Mich wundert, daß du immer das gleiche a hast. Sonst würde ich sagen, du willst den Wert eines Polynoms berechnen...

Da du jedes v mit a malnimmst, bevor du es zur summe zählst, kannst du das auch nachher machen:

p:=1;
FOR i:=1 TO m DO
p:=p*x;
v:= v + p;
s:= s + v;
END_FOR;
s:=s*a;
 
Hallo Zottel,

Zottel schrieb:
Ich würde beim Rechengang ansetzen:
n läuft von 1 bis m. Wenn du eine zusätzliche variable p einführst und schreibst:

p:=1;
FOR i:=1 TO m DO
p:=p*x;
v:= v + p;
s:= s + v * a;
END_FOR;
Ist P im 1. Durchlauf p=x =x**1;
im 2. Durchlauf p=x*x =x**2;
usw.

Deine Antwort hat mich auf folgende Idee gebracht:
Code:
                      1-x^(n+1)
a * SUMME (für i=0) (-----------) -1
                         1-x
damit habe ich die Schleife nun ganz weg, und hoffentlich wieder eine normale Zykluszeit (noch nicht getestet)
Zottel schrieb:
Mich wundert, daß du immer das gleiche a hast.
Da du jedes v mit a malnimmst, bevor du es zur summe zählst, kannst du das auch nachher machen:
Ja, so einen Mist mache ich öfters :oops: :roll:

mfg
marco
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Anonymous schrieb:
Deine Antwort hat mich auf folgende Idee gebracht:
Code:
                      1-x^(n+1)
a * SUMME (für i=0) (-----------) -1
                         1-x
damit habe ich die Schleife nun ganz weg, und hoffentlich wieder eine normale Zykluszeit (noch nicht getestet)
Verstehe ich jetzt noch nicht. Das heißt, du hast benutzt eine gschlossene Formel für den Wert der Summe? Warum steht da dann: (für i=0) ?
Ansonsten: Bei Fließkomma (REAL) geshieht da Potenzieren intern wahrscheinlich über:
x**n = exp(n*ln(x)), wobei die Funktionen exp und ln über ihre Taylorreihen (wikipedia) gebildet werden.
Ohne zu wissen, wieviel Glieder der Reihe berechnet werden müssen,nehme ich mal 8 an. Das bedeutet, daß 16 Multiplikationen und Additionen für die Berechnung der Potenz gebraucht werden.
Der Sonderfall, daß n eine ganze Zahl ist, wird nicht extra behandelt. Ohne Floating-Point Hardware ist eine Addition aufwendiger als eine Multiplikation, mit FP-Hardware sollte es egal sein.
Daher die Schätzung, daß eine einzelne Potenzierung ab N=32 schneller sein könnte als 32 Multiplikationen in einer Schleife.
Für ganzzahlige n gäbe es noch einige Tricks, die Berechnung von x^n zu verkürzen:
Für n<=63:
x2=x*x
x4=x2*x2
x8=x4*x2
x16=x4*x4
x32=x8*x4
P=1.0
if ((n and 32)<>0) then
P=P*x32
n=n-32
endif
if ((n and 16)<>0) then
P=P*x16
n=n-16
endif
if ((n and 8)<>0) then
P=P*x8
n=n-8
endif
if ((n and 4)<>0) then
P=P*x4
n=n-4
endif
if ((n and 2)<>0) then
P=P*x2
n=n-2
endif
if ((n and 1)<>0) then
P=P*x
n=n-1 // kann man sich sparen
endif
Berechnet also x**n mit maximal 11 Gleitkomma-Multiplikationen. Das ist jetzt kein Spezieller SPS-Code. Dort würde man besser n in ein MB schreiben, so daß statt:
if ((n and 2)<>0)
U Mx.1

und statt:
n=n-2
R Mx.1

geschrieben werden könnte.
 
Zottel schrieb:
Verstehe ich jetzt noch nicht. Das heißt, du hast benutzt eine gschlossene Formel für den Wert der Summe? Warum steht da dann: (für i=0) ?
Ja genau, ich benutze eine geschlossene Formel zur Berechnung der Summe der Potenzen.

Ich hab keine Ahnung wie ich hier ein Summenzeichen einfügen soll.
Mit i=0 meinte ich das n bei 0 anfängt <- ok, blöd ausgedrückt, sorry

Ansonsten: Bei Fließkomma (REAL) geshieht da Potenzieren intern wahrscheinlich über:
x**n = exp(n*ln(x)), wobei die Funktionen exp und ln über ihre Taylorreihen (wikipedia) gebildet werden.
Wenn der SCL-Compiler wieder irgendwie AWL daraus generiert, wird das wohl stimmen.

Ohne zu wissen, wieviel Glieder der Reihe berechnet werden müssen,nehme ich mal 8 an. Das bedeutet, daß 16 Multiplikationen und Additionen für die Berechnung der Potenz gebraucht werden.
Der Sonderfall, daß n eine ganze Zahl ist, wird nicht extra behandelt. Ohne Floating-Point Hardware ist eine Addition aufwendiger als eine Multiplikation, mit FP-Hardware sollte es egal sein.
Daher die Schätzung, daß eine einzelne Potenzierung ab N=32 schneller sein könnte als 32 Multiplikationen in einer Schleife.

jetzt kann ich nicht mehr ganz folgen :?

Für ganzzahlige n gäbe es noch einige Tricks, die Berechnung von x^n zu verkürzen:
Für n<=63:
x2=x*x
x4=x2*x2
x8=x4*x2
x16=x4*x4
x32=x8*x4
P=1.0
if ((n and 32)<>0) then
P=P*x32
n=n-32
endif
if ((n and 16)<>0) then
P=P*x16
n=n-16
endif
if ((n and 8)<>0) then
P=P*x8
n=n-8
endif
if ((n and 4)<>0) then
P=P*x4
n=n-4
endif
if ((n and 2)<>0) then
P=P*x2
n=n-2
endif
if ((n and 1)<>0) then
P=P*x
n=n-1 // kann man sich sparen
endif
Berechnet also x**n mit maximal 11 Gleitkomma-Multiplikationen. Das ist jetzt kein Spezieller SPS-Code. Dort würde man besser n in ein MB schreiben, so daß statt:
if ((n and 2)<>0)
U Mx.1

und statt:
n=n-2
R Mx.1

geschrieben werden könnte.

Ja n fängt bei 1 an und wird inkrementiert, also ganzzahlig.
Diesen Teil werde ich mir noch mal ganz in Ruhe zu Gemüte führen :D

mfg
marco
 
Bei geschlossenen Formeln kann der konstante Teil über eine LookUp-Tabelle realisiert werden, die einmal berechnet wird. Dies kann dann sogar auf dem PC erfolgen und in einen DB in Quelle eingetragen werden.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Anonymous schrieb:
jetzt kann ich nicht mehr ganz folgen :?
Tayloreihe ist bekannt? Ohne Garantie auf Richtigkeit:
exp(x)=x+1/2*x**2+1/(2*3)*x**3+1/(2*3*4)*x**4+...+1/n!*x**n
Etwas ähnliches gibt es für ln(x).
Da es unendlich viele Summanden sind, die aber immer kleiner werden, kann man die ersten berechnen und alle weglassen, deren Beitrag bei einer gegebenen Rechengenauigkeit verschwindet.
Ich habe einfach geschätzt, daß man in beideen Reihen die ersten acht Summanden braucht. Da man jeden berechnen kann in dem man den vorigen mit x malnimmt und durch n teilt, kommt man für jeden weiteren mit einer zusätzlichen Multiplikation und einer Addition aus.
Daher die Schätzung von je 16 für exp(n*ln(x)).
 
Hallo Zottel

jetzt hab ich verstanden wo Du drauf hinaus willst.
Zottel schrieb:
Für ganzzahlige n gäbe es noch einige Tricks, die Berechnung von x^n zu verkürzen:

Das könnte sogar funktionieren

1.) Die SPS scheint nicht zu unterscheiden ob der Exponent eine reelle oder natürlische Zahl ist.
2.) Die Ausführungszeiten der CPU:

z.B. CPU315
EXP -> 449us
*R -> 3,2us
Da kann ich doch schon einige arithmetische Operationen bearbeiten, bis an die Zeit von "EXP" rankomme

Allerdings glaube ich, das diese Art der Optimierung für die Praxis nicht besonders relevant ist.

mfg
marco

PS: hab mich mal angemeldet :D
 
Zurück
Oben