Forum: Compiler & IDEs Optimierung von Rechnungen und If Schleife


von Manax (Gast)


Lesenswert?

int choosetable(){
if(startup==1){ allticks=15000; }
uint32_t calcticks=allticks;
if (allticks >= 3191) {
  if(allticks>= 11905 ){
                     coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[0]))/1800));
               coiloff=coilon+loadtime;
             startup=0;
             return 0;
             }//253-1260
  if(allticks>= 7075  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[2]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//1261-2120
  if(allticks>= 5034  ){
              coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[3]))/1800));
              coiloff=coilon+loadtime;
              return 0;
             }//2121-2980
  if(allticks>= 3906  ){
                       coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[4]))/1800));
                  coiloff=coilon+loadtime;
             return 0;
             }//2981-3840
  if(allticks>= 3191  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[5]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//3841-4700
}else{
  if(allticks>= 2698  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[6]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//4701-5560
  if(allticks>= 2336  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[7]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//5561-6420
  if(allticks>= 2060  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[8]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//6421-7280
  if(allticks>= 1843  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[9]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//7281-8140
  if(allticks>= 1667  ){
                   coilon=allticks- 
(loadtime+((calcticks*(vorzuendung+zzp1[10]))/1800));
             coiloff=coilon+loadtime;
             return 0;
             }//8141-9000
  }
return 0;
}


Oben angefügt habe ich einen Codeabschnitt meines Programms mit dem ich 
leider so meine Probleme habe.

Die If Schleifen brauchen im Worst-case 25µs bei 20 Mhz und die Rechnung 
für den Wert coilon leider 70 µs.
Das Problem bei des Sache ist nur, dass es sich hier um eine 
zeitkritische Anwendung handelt bei der Werte für einen gesamten 
Durchlauf von 20-50 µs äußerst praktisch wären.

Gibt es Möglichkeiten den Code zu optimieren um Zeit zu sparen ?

Wenn ich oben calcticks als 16 bit Variable passiert spart es Zeit aber 
das Ergebniss wird zu ungenau. Dasselbe passiert wenn ich statt zu 
dividieren schieben um 11 benutze. Gibt es andere Möglichkeiten der 
optimierung ? Vor allem die IFs stören mich.


Bitte helft mir ich hab schon masseenhaft Foren ergebnisslos durchsucht.

mfg Manax

von Michael U. (amiga)


Lesenswert?

Hallo,

http://if-schleife.de/

auch wenn ich mir Dein Problem noch nicht genauer anegschaut habe...

Gruß aus Berlin
Michael

von Jan M. (mueschel)


Lesenswert?

Bitte poste den Code noch einmal als Anhang, dann stimmt sowohl die 
Einrueckung als auch das Code-Highlighting und man kann ihn viel besser 
lesen.

von mki (Gast)


Lesenswert?

@Michael:
lol... ist mir gar nicht aufgefallen. Jeder weis doch was er meint. Also 
jetzt sei nicht so kleinlich ;-).

Ansonsten:
Vielleicht ist eine "case-Schleife" schneller.

von micha (Gast)


Lesenswert?

Schmeiss die Division mit dem konstanten Faktor 1800 raus. Warum 
schleppst Du das mit Dir rum? Läßt sich "vorzuendung+zzp1[x]" eventuell 
im Voraus berechnen?

von Route_66 (Gast)


Lesenswert?

Assembler???

von Peter D. (peda)


Lesenswert?

Man kann es erstmal übersichtlicher schreiben:
1
void choosetable( void )
2
{
3
  uint8_t idx;
4
5
  if( startup==1 )
6
    allticks=15000;
7
8
  switch( allticks ){
9
    case 11905 ... 65535: idx = 0; startup = 1; break;
10
    case 7057 ... 11904: idx = 2; break;
11
    case 5034 ... 7056: idx = 3; break;
12
    case 3906 ... 5033: idx = 4; break;
13
    case 3191 ... 3905: idx = 5; break;
14
    case 2698 ... 3190: idx = 6; break;
15
    case 2336 ... 2697: idx = 7; break;
16
    case 2060 ... 2335: idx = 8; break;
17
    case 1843 ... 2059: idx = 9; break;
18
    case 1667 ... 1842: idx = 10; break;
19
    default: return;
20
  }
21
  coilon = allticks - loadtime
22
  - ((uint32_t)allticks*(vorzuendung+zzp1[idx]))/1800;
23
  coiloff = coilon+loadtime;
24
}

Wenn Du mal in Worten beschreiben würdest, wozu das gut ist, könnte man 
wohl auch noch optimieren.


Peter

von Rolf Magnus (Gast)


Lesenswert?

> case 11905 ... 65535: idx = 0; startup = 1; break;

Man sollte sich aber bewußt darüber sein, daß das kein Standard-C, 
sondern eine Erweiterung des gcc ist.

von Sven P. (Gast)


Lesenswert?

Und dass wir hier im GCC-Forum sind :-) (ack)

von Rolf Magnus (Gast)


Lesenswert?

Das war mir schon klar, sonst hätte ich anders geantwortet. Ich find's 
nur trotzdem gut, solche Abhängigkeiten zu erwähnen.

von Sauger (Gast)


Lesenswert?

Rolf Magnus schrieb:
>> case 11905 ... 65535: idx = 0; startup = 1; break;
>
> Man sollte sich aber bewußt darüber sein, daß das kein Standard-C,
> sondern eine Erweiterung des gcc ist.

als Pseudocode betrachten, ist lesbarer.
MfG

von Peter D. (peda)


Lesenswert?

Manax schrieb:
> Wenn ich oben calcticks als 16 bit Variable passiert spart es Zeit aber
> das Ergebniss wird zu ungenau. Dasselbe passiert wenn ich statt zu
> dividieren schieben um 11 benutze.

Warum ist das zu ungenau ?
Was sind das überhaupt für nen Haufen Werte?
Sind das Konstanten, kannst Du doch beim Compilieren den Korrekturfaktor 
2048/1800 einfach mit reinrechnen lassen.
Die Division ist jedenfalls das mit Abstand teuerste.
Und wenns ein ATmega ist, ist die Multipikation auch nicht so schlimm.

Wenn "allticks" bei jedem Aufruf konstant hoch- oder runterzählt, dann 
kann man die Rechnung auf eine einzige Addition verkürzen.
Die Tabelle enthält dann nicht mehr Faktoren, sondern die Schrittweite.
Das ist dann am schnellsten.

> Vor allem die IFs stören mich.

Die stören vielleicht optisch, von der Rechenzeit her sind es Pinats.

Was mich daran stört, ist das 10-fach Copy&Paste-Monster.
Es wird doch fast immer das gleiche gemacht, als ab damit ans Ende und 
nicht 10-mal kopieren.


Peter

von Manax (Gast)


Lesenswert?

Vielen dank für eure schnelle Hilfe.
Der Hinweis mit dem case hat mich gerettet wusste gar nicht,dass das so 
funktioniert. (Spart mir schonmal 7µs ) macht die Sache übersichtlicher 
und vor allem erweiterbar.

Assembler kann ich leider nicht programmieren.
Ich würde die Division gerne rausziehen allerdings ist 
vorzuendung+zzp[idx] ein so kleiner Wert, dass die Rechnung viel zu 
ungenau wird.Allticks ist eine Variable.


Zur grundsätzlichen Funktion des Programms:

Dieser Programmteil soll die Zündverzögerung einer Zündung mit 
Verstellkurve errechnen. Der Wert in µs ist gesucht mit einem globalen 
Wert (in 0.2 Grad Schritten )und einem speziellen auf die Drehzahl 
abgestimmten Wert (in 0.2 Grad Schritten).


mfg Manax

von Manax (Gast)


Lesenswert?

p.s. Ich bin fast verzweifelt bis ich den Fehler in der case gefunden 
habe.
Ein arraywert wird übersprungen zzp[1].

mfg

von micha (Gast)


Lesenswert?


von Dominik (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Man kann es erstmal übersichtlicher schreiben:
> void choosetable( void )
> {
>   uint8_t idx;
>   if( startup==1 )
>     allticks=15000;>
>   switch( allticks ){
>     case 11905 ... 65535: idx = 0; startup = 1; break;
>     case 7057 ... 11904: idx = 2; break;
>     case 5034 ... 7056: idx = 3; break;
>     case 3906 ... 5033: idx = 4; break;
>     case 3191 ... 3905: idx = 5; break;
>     case 2698 ... 3190: idx = 6; break;
>     case 2336 ... 2697: idx = 7; break;
>     case 2060 ... 2335: idx = 8; break;
>     case 1843 ... 2059: idx = 9; break;
>     case 1667 ... 1842: idx = 10; break;
>     default: return;
> }

Könnte mir jemand diese GCC Erweiterung erklären, da ich nur Standard 
c(++) behersche.
Prüft der Switch ob sich Werte dazwischen befinden? z.B. zwischen 1667 
... 1842 und wenn ja, wird idx zu 10 gesetzt?

von Rolf Magnus (Gast)


Lesenswert?

> Könnte mir jemand diese GCC Erweiterung erklären, da ich nur Standard
> c(++) behersche.

Das GCC-Handbuch kann das.

> Prüft der Switch ob sich Werte dazwischen befinden?

Nicht dazwischen, aber ob sie sich in dem angegebenen Bereich befinden, 
also inklusive den angegebenen Grenzwerten.

> z.B. zwischen 1667 ... 1842 und wenn ja, wird idx zu 10 gesetzt?

Ja.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.