Forum: Mikrocontroller und Digitale Elektronik Vereinfachung einer "C" Funktion


von Martin M. (ats3788)


Lesenswert?

Hallo
Ist nicht so wichtig doch ich dachte mir
fragste mal.

unsigned char GetPlot(char Kurve){
     int dummy;
     dummy = (round( pow(2, Kurve)));
     return ( dummy >> 1 );
}

funktioniert wunderbar nur kann man die Funktion, vereinfachen?

Das dumme dabei 2hoch8 ergibt 256 also 1 byte + 1
deswegen brauche ich den int dummy.
Vielleicht lerne ich mal wieder was

Danke im voraus

von Flo (Gast)


Lesenswert?

Martin M. schrieb:
> unsigned char GetPlot(char Kurve){
>      return 1<<(Kuve-1);
> }

von Jim M. (turboj)


Lesenswert?

Da gibt es doch nur einen winzigen Wertebereich für die Eingabe "Kurve". 
IMO wäre dann ein switch(Kurve){} effizienter, allerdings auch viel mehr 
Zeilen in C.

von Felix Adam (Gast)


Lesenswert?

Wenn "Kurve" immer positiv ist, müsste dann nicht

unsigned char Kurve

als Übergabeformat eingetragen sein? Dann würde auch Dummy zu einem 
uint16 und somit könnte der Compiler das wahrscheinlich vereinfachen.

von Oliver S. (oliverso)


Lesenswert?

Neben der obligatorischen Frage : Warum? stellt sich noch die Frage : 
Hä?

Was genau soll die Funktion denn machen?

Oliver

von Klaus (Gast)


Lesenswert?

Karl Heinz wird das alles erklären. :-)

Aber mal so hingefragt: Was ist:

2^1 (pow(2,1))

2^2 (pow(2,2))

2^3 (pow(2,3))

Hint: Hier liegt der Sonderfall der Basis 2 und von integer-Exponenten 
vor.

von Matthias L. (Gast)


Lesenswert?

1
 dummy = (round( pow(2, Kurve)));
2
     return ( dummy >> 1 );

Du rechnest also Zwei hoch Kurve, um dann das Ergebins durch zwei zu 
teilen.

Warum dann nicht gleich Zwei hoch (Kurve-1) ?

EDIT:
Da Kurve immmer eine Ganzzahl ist, kommen auch nur Ganzzahlen als 
Ergebnis von pow raus. Somit sollte doch das round unnötig sein...?

von Klaus (Gast)


Lesenswert?

Matthias L. schrieb:
>
1
>  dummy = (round( pow(2, Kurve)));
2
>      return ( dummy >> 1 );
3
>
>
> Du rechnest also Zwei hoch Kurve, um dann das Ergebins durch zwei zu
> teilen.
>
> Warum dann nicht gleich Zwei hoch (Kurve-1) ?
>
> EDIT:
> Da Kurve immmer eine Ganzzahl ist, kommen auch nur Ganzzahlen als
> Ergebnis von pow raus. Somit sollte doch das round unnötig sein...?

Und das pow ist auch gleich unnötig. Siehe meine Frage oben.

Wozu erst in double rechnen, wenn sowohl die Argumente als auch das 
Resultat integer sind?

Aber wie gesagt: Das wird Karl Heinz alles erklären, und:

"Vielleicht lernst Du mal wieder was".

So ein paar Grundlagen müssen ja auch mal gelernt werden.

Was noch bleibt, sind implzite Umwandlungen und Promotion.

von Karl H. (kbuchegg)


Lesenswert?

Klaus schrieb:

> Aber wie gesagt: Das wird Karl Heinz alles erklären, und:

Was soll ich da gross erklären?

Offenbar kann 'Kurve' sowíeso nur Werte zwischen 0 und 8 annehmen. 
Ansonsten würde der Return Datentyp keinen Sinn machen. Also wozu lange 
rumrechnen? Bei 9 verschiedenen Ergebnissen  macht man ein Array, in dem 
man die Werte im voraus ausrechnet und einen davon zurückliefert und gut 
ists.
Getreu dem alten Motto: Space for Time

von Klaus (Gast)


Lesenswert?

Karl H. schrieb:
> Klaus schrieb:
>
>> Aber wie gesagt: Das wird Karl Heinz alles erklären, und:
>
> Was soll ich da gross erklären?

Nichts. Entschuldigung.

von Martin M. (ats3788)


Lesenswert?

Danke für die vielen Antworten
ja round ist unnötig kommt noch von der funktion wo ich sinus noch drin 
hatte
sorry

nein kein array ich wollte nur wissen ob
ich den Buffer dummy int 16 bit weglassen könnte.

Als Hintergrund

Ich gebe auf ein LED Display mit 8 x 16 Led's
Das mache ich mit spi und zwei PIC16F887

Muster aus und da dachte fängst Du mal mit einer Sinuskurve an. .-)

von Karl H. (kbuchegg)


Lesenswert?

Martin M. schrieb:

> nein kein array ich wollte nur wissen ob
> ich den Buffer dummy int 16 bit weglassen könnte.

Mach dir deswegen keinen Kopf. Compiler sind gut darin, Variablen 
rauszuwerfen, die keiner braucht. Kümmere du dich um die Logik und 
überlass den Rest dem Compiler.

Wenn du die Funktion vereinfachen willst, dann sieh zu, dass du das pow 
los wirst und auch das round. Dort hast du Potential. Aber über 
funktionslokale Variablen brauchst du dir keinen Kopf machen, ausser es 
sind viele und ausser es sind Arrays. Aber aus deiner Funktion intern 
ein
1
unsigned char GetPlot(char Kurve){
2
  return (int)( (round( pow(2, Kurve))) ) >> 1;
3
}
zu machen, ist für eine Compiler eine leichte Übung. Nicht jede 
Variable, die in deiner Funktion vorkommt, führt auch dazu, dass 
irgendwo Speicher dafür reserviert wird. Compiler können das problemlos, 
dass sie über die Verwendung der Register Buch führen und welcher Wert 
wann in welchem Register liegt. Wenn es reicht, diesen Wert von dort 
wieder weiter zu verwenden, gibt es keinen Grund, warum der Wert jemals 
ins SRAM gespeichert werden soll. Wenn es nichts zu speichern gibt, 
braucht man auch keine Speicherreservierung dafür.

Aber all das soll dich nicht kümmern. Du kümmerst dich um die Logik und 
schreibst sie so, wie es für dich am verständlichsten ist. Wenn es mit 
Hilfsvariablen für dich am verständlichsten ist, dann schreibst du das 
eben mit Hilfsvariablen und der Compiler formt das wieder so um und 
stutzt es zurecht, dass die Hilfsvariable rausfliegt. Die dazu 
notwendige Technik beherrschen die Compilerbauer seit Jahrzehnten.

: Bearbeitet durch User
von Mark B. (markbrandis)


Lesenswert?

Karl H. schrieb:
> Kümmere du dich um die Logik und überlass den Rest dem Compiler.

Genau so sieht's aus.

Wenn man nicht gerade einen total ungeeigneten Algorithmus verwendet, 
dann ist nahezu jeder Code gut solange er:

-korrekte Ergebnisse liefert (durch Tests nachgewiesen)
-lesbar und verständlich ist (auch nach Jahren noch)

Alles andere ist Zeit vergeudet an der falschen Stelle.

Übrigens: Für nicht genutzte Rechenzeit oder nicht genutzten Speicher 
gibt es kein Geld zurück ;-)

von Martin M. (ats3788)


Lesenswert?

Danke Karl Heinz

Ich komme aus der Pascal Welt
und man lernt indem man die Philosophie einer anderen
Sprache versteht.

Einen guten Rutsch

von M. K. (sylaina)


Lesenswert?

Karl H. schrieb:
> Klaus schrieb:
>
>> Aber wie gesagt: Das wird Karl Heinz alles erklären, und:
>
> Was soll ich da gross erklären?
>
> Offenbar kann 'Kurve' sowíeso nur Werte zwischen 0 und 8 annehmen.
> Ansonsten würde der Return Datentyp keinen Sinn machen. Also wozu lange
> rumrechnen? Bei 9 verschiedenen Ergebnissen  macht man ein Array, in dem
> man die Werte im voraus ausrechnet und einen davon zurückliefert und gut
> ists.
> Getreu dem alten Motto: Space for Time

Genau das hab ich mich auch gefragt als ich den Post gelesen habe.
Ich würde es so schreiben:
1
unsigned char GetPlot(unsigned char Kurve) {
2
   int dummy[9] = {1, 2, 4, 8, 16, 32, 64, 128, 256};
3
   if ( ((unsigned int)Kurve-1) > 8 ) return -1; //parameter ausserhalb des zulaessigen Wertebereichs
4
   return (unsigned char)dummy[ (unsigned int)Kurve-1 ];
5
}

In C bin ich nicht sonderlich gut aber muss/sollte der Rückgabewert 
nicht auch unsigned char sein wenn die Funktion unsigned char ist?
@Martin
Und da ich es ungewöhnlich finde, dass du da einen char als 
Funktionsparameter hast: Du willst wirklich den Intergerwert des 
übergebenen Chars benutzen, es ist nicht so dass da als Zeichen eine 
z.B. 6 (hat den Integerwert 54) kommt?

von Peter II (Gast)


Lesenswert?

Michael K. schrieb:
> Ich würde es so schreiben

die ganzen gast sind unnötig.
1
unsigned char GetPlot(unsigned char Kurve) {
2
   unsigned char dummy[] = {1, 2, 4, 8, 16, 32, 64, 128, 256};
3
   //parameter ausserhalb des zulaessigen Wertebereichs
4
   if ( Kurve > 9 || Kurve < 1  ) {
5
      return -1;
6
   } 
7
   return dummy[ Kurve-1 ];
8
}

Cast verwendet man nur wenn man den Compiler zu etwas zwingen will, 
dafür sehe ich hier keine Grund.

von Shift (Gast)


Lesenswert?

Warum überhaupt ein Array ?

Im oben genannten Fall ist ein Shift-Left viel schneller und braucht 
weniger Code als ein Array.

Also:
1
unsigned char GetPlot(unsigned char Kurve) {
2
   //parameter ausserhalb des zulaessigen Wertebereichs
3
   if ( Kurve > 8 || Kurve == 0  ) {
4
      return -1;
5
   } 
6
   return 1 << (Kurve-1);
7
}

von Peter II (Gast)


Lesenswert?

Shift schrieb:
> Im oben genannten Fall ist ein Shift-Left viel schneller und braucht
> weniger Code als ein Array.

schnell ist abhängig von der CPU. Bei den Atmels kann das Array durchaus 
schneller sein.

von Rolf M. (rmagnus)


Lesenswert?

Peter II schrieb:
> Shift schrieb:
>> Im oben genannten Fall ist ein Shift-Left viel schneller und braucht
>> weniger Code als ein Array.
>
> schnell ist abhängig von der CPU. Bei den Atmels kann das Array durchaus
> schneller sein.

Zumindest bei AVR. Da dieser nicht shiften kann, muss er einen Shift 
über eine variable Anzahl von Bits über wiederhote Additionen in einer 
Schleife nachbilden.

Michael K. schrieb:
> unsigned char GetPlot(unsigned char Kurve) {
>
> if ( ((unsigned int)Kurve-1) > 8 ) return -1; //parameter ausserhalb
> des zulaessigen Wertebereichs

Wenn man negative Werte zurückliefern will, sollte der Return-Typ aber 
auch vorzeichenbehaftet sein.

von Karl H. (kbuchegg)


Lesenswert?

Shift schrieb:
> Warum überhaupt ein Array ?
>
> Im oben genannten Fall ist ein Shift-Left viel schneller und braucht
> weniger Code als ein Array.
>
> Also:
>
1
> unsigned char GetPlot(unsigned char Kurve) {
2
>    //parameter ausserhalb des zulaessigen Wertebereichs
3
>    if ( Kurve > 8 || Kurve == 0  ) {
4
>       return -1;
5
>    }
6
>    return 1 << (Kurve-1);
7
> }
8
>

Kommt auf den Prozessor an.
Auf einem AVR muss dein 1<<(Kurve-1) zu dem hier umgeformt werden:
1
....
2
    unsigned char mask = 0x01;
3
    {
4
      unsigned char tmp;
5
      for( tmp = Kurve; tmp > 0; tmp-- )
6
        mask <<= 1;
7
    }
8
    return mask;

immer noch überzeugt, dass das in allen Fällen schneller ist als ein 
simpler Array Zugriff, d.h. eine Dereferenzierung eines Basepointer + 
Offset? Vor allen Dingen dann, wenn man das Array static macht, so dass 
es nicht jedesmal neu initialisiert werden muss.

Auf einem AVR willst du keine Shifts mit variabler Anzahl an Bits haben, 
wenn es auch andere Möglichkeiten gibt.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

sinnvollerweise sollte das Array aber noch const static sein. Und die 
Anmerkung mit dem return -1 sollte man auch berücksichtigen.

also neuer versuch
1
unsigned char GetPlot(unsigned char Kurve) {
2
   static const unsigned char dummy[] = {1, 2, 4, 8, 16, 32, 64, 128, 256};
3
   //parameter ausserhalb des zulaessigen Wertebereichs
4
   Kurve--;
5
   if ( Kurve > sizeof(dummy) ) {
6
      return 0;
7
   } 
8
   return dummy[ Kurve ];
9
}

von Conny G. (conny_g)


Lesenswert?

Returnwert -1 und unsigned char geht doch nicht zusammen, oder?
Müsste int sein, damit man das -1 auch rausbekommt.

Ah, ja, Peter hat's schon geschrieben.

: Bearbeitet durch User
von M. K. (sylaina)


Lesenswert?

Ich sagte ja, so doll bin ich in C nicht. Und ob jetzt Shift oder Array 
schneller ist auf dem AVR weiß/wusste ich auch nicht. Und klar, das 
return -1 ist für unsigned auch wenig schön. In der Regel schreib ich 
ein Programm/Funktion erst mal so runter und kümmere mich dann um die 
Warnings die mir der Compiler nennt. Ich hab ETechnik studiert und unser 
Informatik-Prof hat uns beigebracht: Es gibt keinen Grund Warnings zu 
ignorieren! Ich hab aber obige Funktion nicht dem Compiler zum 
verarbeiten gegeben gehabt, das war mehr frei Schnautze runter 
geschrieben ;)

von M. K. (sylaina)


Lesenswert?

Conny G. schrieb:
> Returnwert -1 und unsigned char geht doch nicht zusammen, oder?
> Müsste int sein, damit man das -1 auch rausbekommt.
>
> Ah, ja, Peter hat's schon geschrieben.

Richtig, da käme 255 raus und das ist auch das Problem, dass ich mit dem 
Funktionswert sehe: wie kann die Funktion 256 zurückliefern wenn sie 
unsigned char ist? Das geht nur bis 255 ;)

von Karl H. (kbuchegg)


Lesenswert?

Conny G. schrieb:
> Returnwert -1 und unsigned char geht doch nicht zusammen, oder?
> Müsste int sein, damit man das -1 auch rausbekommt.

Die erste Frage sollte allerdings lauten:
Kann es überhaupt passieren, dass hier der Funktion ein ungültiges 
Argument übergeben wird oder ist das durch die Vorgeschichte schon 
ausgeschlossen und es reicht in diesem Fall (wenn überhaupt) zb immer 
das Ergebnis für 0 zu liefern.

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:

> unser
> Informatik-Prof hat uns beigebracht: Es gibt keinen Grund Warnings zu
> ignorieren!

Das ist auch richtig so.
In der professionellen Programmierung wird das so gehandhabt, dass der 
Compiler auf dem höchsten (oder zweithöchsten) Warninglevel einen 
Programmtext ohne jegliche Warnung compilieren muss. Alles andere wird 
als fehlerhaft gewertet und muss behoben werden. Egal ob echter Fehler 
oder Warnung. Nur allzuoft sind Warnungen tatsächliche Probleme, die 
nicht ignoriert werden können.

von M. K. (sylaina)


Lesenswert?

Peter II schrieb:
> sinnvollerweise sollte das Array aber noch const static sein. Und die
> Anmerkung mit dem return -1 sollte man auch berücksichtigen.

Warum static? Sorgt das nicht dafür, dass ein Teil des RAMs für das 
Array reserviert bleibt auch wenn die Funktion grade gar nicht benutzt 
wird?
Und return 0 würde ich auf keinen Fall machen, ein retrun 0 lese ich 
immer als "kein Fehler", hier wäre aber ein Fehler aufgetreten. Ob ich 
mich nach 5 Monaten noch dann dabei erinnern würde, wenn ich mir den 
Code noch mal anschaue, dass das return 0 hier dann bedeutet, dass ein 
Fehler auftrat? Ne, da auf jeden Fall was anderes, am liebsten halt ein 
return -1 und da IMO die funktion eh einen anderen Datentyp als unsigned 
char braucht würde ich hier gleich was signed benutzen.

von Karl H. (kbuchegg)


Lesenswert?

Michael K. schrieb:
> Peter II schrieb:
>> sinnvollerweise sollte das Array aber noch const static sein. Und die
>> Anmerkung mit dem return -1 sollte man auch berücksichtigen.
>
> Warum static? Sorgt das nicht dafür, dass ein Teil des RAMs für das
> Array reserviert bleibt auch wenn die Funktion grade gar nicht benutzt
> wird?

Tut es.
Aber erstens sind es nur 8 Byte und zweitens fällt dann die ständige 
Initialisierung des Arrays beim AUfruf der Funktion weg.

Wer will, kann das Array ja auch noch ins Flash legen. Das ist dann der 
speichertechnisch günstigste Fall.

> Und return 0 würde ich auf keinen Fall machen, ein retrun 0 lese ich
> immer als "kein Fehler", hier wäre aber ein Fehler aufgetreten.

Kommt drauf an.
Das ist ganz klar eine Berechnungsfunktion, bei der ein Wert ungleich 0 
ein sinnvolles Resultat ist, während 0 nicht vorkommen kann.

von Peter II (Gast)


Lesenswert?

Michael K. schrieb:
> Warum static? Sorgt das nicht dafür, dass ein Teil des RAMs für das
> Array reserviert bleibt auch wenn die Funktion grade gar nicht benutzt
> wird?

ja und das ist auch gut so, dann muss es nicht jedes mal neu geladen 
werden.

von M. K. (sylaina)


Lesenswert?

Peter II schrieb:
> Michael K. schrieb:
>> Warum static? Sorgt das nicht dafür, dass ein Teil des RAMs für das
>> Array reserviert bleibt auch wenn die Funktion grade gar nicht benutzt
>> wird?
>
> ja und das ist auch gut so, dann muss es nicht jedes mal neu geladen
> werden.

Das ist natürlich ein Argument und wie Karl Heinz schrieb: am Besten im 
Flash liegen lassen ;)

von Rolf M. (rmagnus)


Lesenswert?

Michael K. schrieb:
> Das ist natürlich ein Argument und wie Karl Heinz schrieb: am Besten im
> Flash liegen lassen ;)

Da muss es ja zwangsweise sowieso schon liegen, von daher drängt sich 
das geradezu auf.

von Peter II (Gast)


Lesenswert?

Rolf M. schrieb:
> Da muss es ja zwangsweise sowieso schon liegen, von daher drängt sich
> das geradezu auf.

die wie nicht wissen, auf welcher Hardware es laufen soll. Muss der 
Hinweis const dem Compiler reichen und damit landet es schon im Flash - 
außer den atmels.

von M. K. (sylaina)


Lesenswert?

Peter II schrieb:
> die wie nicht wissen, auf welcher Hardware es laufen soll.

Wissen wir aber:

Martin M. schrieb:
> Das mache ich mit spi und zwei PIC16F887

;)

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.