ATMEGA8 und Long?

OP #1617924
Hallo,

also es geht darum aus vielen Werten einen Mittelwert zu berechnen.
Nun diese Werte können sich zwischen 0 und 20000 bewegen.
Sollte ich nun 4 mal 20000 hereinbekommen habe ich einen overflow,
da ein integer ja nur bis 65535 geht.
Nun wie initialisier ich einen long richtig auf dem ATMEGA8?
Vor einiger Zeit hatte ich ein ähnliches Problem, hab mich dann aber 
nicht weiter mit long beschäftig da ich einen anderen Lösungsansatz 
gefunden habe.
1
      //Algorithmus zur Leitungsberechnung
2
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
3
      
4
      uiMittelPuffer[iMittelCounter]=uiPuffer;
5

6

7
      if (iMittelCounter==2)
8
      {
9
        uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;
10

11
        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
12
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen
13

14
        //Typkonvertierung für "lcd_puts"- Funktion
15
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);
16

17
        iMittelCounter=0;
18
      }

uiMittelPuffer ist ein integer Array, folgendermaßen initialisiert 
zusammen mit uiPuffer:
1
unsigned int uiPuffer,uiMittelPuffer[4];

Ich würde den Mittelwert aber lieber aus mehr als 3 Werten ermitteln.
Kann mir jemand Helfen?

MFG Julian
Julian Schild schrieb:
>
> Aber warum kann ich nicht einfach
1
 long lPuffer;
 schreiben?

Kannst du

uint32_t macht nur etwas klarer, dass du hier 32 Bit haben willst. Bei 
einem long alleine, weiß wieder kein Mensch auswendig, wieviele Bits das 
sind. Auf deinem AVR sind es 32, auf einem PC sind es wieviele?

Pass lieber auf, dass du hier
1
    uiPuffer=(uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2])/3;

nicht patzt :-)
OP
Hallo Karl,
kannst du dich ein wenig genauer ausdrücken?
Da ich es selber geschrieben habe bin ich der Überzeugung, dass es 
passt.
Also die Selbstkorrektur ist immer um einiges schwieriger ;).

Ich denk es mir so:
Ich addiere 3 Elemnte von diesem Feld um dividiere durch 3.
Somit sollte es eigentlich der Mittelwert sein.

MFG
OP
Hallo,
habe es nun so gelöst:
1
      uiPuffer=(20*usigetADU_10Bit(1))-(usigetADU_10Bit(1)*46/102);
2
      
3
      uiMittelPuffer[iMittelCounter]=(uiPuffer<<2);
4

5
      // Mittelwertbildung
6
      if (iMittelCounter==3)
7
      {
8
        uiPuffer=uiMittelPuffer[0]+uiMittelPuffer[1]+uiMittelPuffer[2]+uiMittelPuffer[3];
9

10
        usiPuffer1=uiPuffer/1000;      // Ganzzahl in W
11
        usiPuffer2=((uiPuffer%1000)/10);  //Nachkommastellen
12

13
        //Typkonvertierung für "lcd_puts"- Funktion
14
        sprintf(cPuffer,"%2d.%dW",usiPuffer1,usiPuffer2);
15

16
        iMittelCounter=0;
17
      }

Die Division durch 4 lässt sich einfach durch das verschieben um 2 
Stellen
darstellen. Bevor die Werte nun ins Array gehen werden sie bereits 
ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow 
nahe kommt.

MFG
Gast
Hi Julian,

Julian Schild schrieb:
> Bevor die Werte nun ins Array gehen werden sie bereits
> ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow
> nahe kommt.
In Deinem Code teilst Du aber nicht durch 4, sondern multiplizierst 
damit.
Außerdem macht es sehr wohl einen Unterschied, ob Du erst alle Zahlen 
durch 4 teilst und dann aufsummierst, oder erst aufsummierst und dann 
durch vier teilst (Stichwort Ungenauigkeit)...
Generell gilt: möglichst spät dividieren.

Viele Grüße
OP
Ampfing schrieb:
> In Deinem Code teilst Du aber nicht durch 4, sondern multiplizierst
> damit.

Danke, du hast natürlich recht.

> Außerdem macht es sehr wohl einen Unterschied, ob Du erst alle Zahlen
> durch 4 teilst und dann aufsummierst, oder erst aufsummierst und dann
> durch vier teilst (Stichwort Ungenauigkeit)...
> Generell gilt: möglichst spät dividieren.

Auch hier hast du recht. Aber ab dem Wert 4 gibt es keinen Fehler mehr 
der bei einer späteren Division nicht auch auftreten würden.
Und wenn mein Wertebereich von 0-20000 geht , dann hab ich einen Fehler 
von 0.02%. Das sollte OK sein.

MFG
Julian Schild schrieb:

> Die Division durch 4 lässt sich einfach durch das verschieben um 2
> Stellen
> darstellen.

Wenn du durch 4 dividieren willst, dann schreibe auch eine Division 
durch 4.

WENN diese Division auf dem Prozessor durch eine Veschiebung erreicht 
werden kann UND diese Schieberei tatsächlich schneller ist als 
Dividieren DANN weiß das der Compiler und ersetzt dir das auf 
Assemblerebene.

Generell: Benutze immer die Operation, die die Absicht am besten 
ausdrückt. An dieser Stelle ist die Absicht durch 4 zu dividieren. Also 
schreib auch Division.

 Bevor die Werte nun ins Array gehen werden sie bereits
> ge4telt um niemals so hohe Werte zu erreichen, dass man einem Overflow
> nahe kommt.

Wozu dann der long?


Worauf ich hinaus wollte:
Bei deiner Summierung ist es völlig unerheblich ob du als 
Ergebnisdatentyp einen long hast oder nicht. Bei einer Operation 
betrachtet der Compiler die beiden Operanden. Nur deren Datentyp zählt 
bei der Auswahl der Operation.

  long i;
  int  j, k;

  i = j + k;

j ist ein int, k ist ein int. ALso wird die Addition mit einer 
int-Addition durchgeführt. Erst dieses Ergebnis wird auf long 
umgewandelt.

wenn also i gleich 32765 ist und k gleich 32765, dann hast du einen 
Overflow! Die Tatsache dass die Ergebnisvariable als long das richtige 
Ergebnis aufnehmen könnte, ist unerheblich. Dieser Datentyp long kommt 
erst dann ins Spiel, wenn das Kind (die Addition) schon in den Brunnen 
gefallen ist.
OP
Nachtrag der Richtigkeithalber:
1
uiMittelPuffer[iMittelCounter]=(uiPuffer/4);


@Franz:
Den Long wollte ich vorher haben. Jetzt brauch ich ihn natürlich nicht 
mehr.

Danke für dein Beispiel, das war mir nicht bewusst.



Noch mal zur Genauigkeit:
Durch, dass verschieben hätte ich nur einen Fehler wenn ich ganz kleine 
Werte bekomme, Werte im Bereich von 1-3.
Julian Schild schrieb:

> Noch mal zur Genauigkeit:
> Durch, dass verschieben hätte ich nur einen Fehler wenn ich ganz kleine
> Werte bekomme, Werte im Bereich von 1-3.

Na ja.
Du hast immer dann Fehler, wenn sich die Einzelwerte nur um wenig 
unterscheiden.

   200 + 201 + 202 + 203 = 806 / 4 = 201

   200 / 4  + 201 / 4 + 202 / 4 + 203 / 4 = 50 + 50 + 50 + 50 = 200


wenn du damit leben kannst, ist es ok.

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 16 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.