www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Multiplikation - Ergebnis falsch


Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

habe ein Mega128 auf dem folgende Multiplikation ein falsches
Ergebnis liefert.

unsigned int x = 0, y = 999;

 x = y * 9

 Ergebnis x = 8910 sollte eigentlich 8991 sein.
 Es fehlen also 9*9 = 81
 Bin echt am verzweifeln. Ich finde den Fehler einfach nicht.
 Hat jemand vielleicht ein Tip wie der Fehler zustande kommt?

Gruß

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
st du sicher, dass du statt
unsigned int x = 0, y = 999;

nicht
unsigned int x = 0, y = 990;

geschrieben hast?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Frei nach Göthe: Mehr Code!

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
oder doch Goethe ?

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Klaus Falser schrieb:
> oder doch Goethe ?

Als Österreicher muss ich das nicht so genau wissen. Oder wusstest du 
wie sich der Herr Alfred Hrdlicka richtig schreibt :-)

Aber um auf die Frage zurückzukommen
> Hat jemand vielleicht ein Tip wie der Fehler zustande kommt?
Du hast einen Bug im Programm.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, bin ganz sicher das y = 999 sind.

hier noch der ganze Code.


void Out(unsigned int wert)
{
 unsigned int x0 = 0, in = 0, wert1 = 0;//
 signed int diff = 0;

    in = wert;

    itoa(in, cm_buff); // Wert auf Display ausgeben
    wrlcd_ziffK(0);


   if (in > 2424) {
       in = 2424;
   };

   if (in < 1425) {
       in = 1425;
   };

    wert1=(in - 1425);

   itoa(wert1, cm_buff); Wert auf Display ausgeben
   wrlcd_ziffK(1);

    diff = (wert1 - x2); // x2 ist eine Globale Variable

        if (diff > 21 | diff < -21) {

            x_wert = ((x2 + wert1)/2);
            x2 = x_wert;
        }
        else  {

            x3 = x2*9; // !!!!!!!!!!! Hier ist x3 nur 8910 wenn x2 = 999

            itoa(x3, cm_buff); // Wert auf Display ausgeben
            wrlcd_ziffK(0);

            x_wert = (x3 + wert1)/10;

            itoa(x_wert, cm_buff);
            wrlcd_ziffK(1);

            x2 = x_wert;
        };

        itoa(x_wert, cm_buff); // Wert auf Display ausgeben
        wrlcd_cmbuff(1);

}

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was gibt das Programm wo aus? Welchen Wert hat x2 vor der 
Multiplikation? Glauben/Vermuten hilft da nicht, ihn Anzeigen ist 
besser.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch mehr Goethe: Noch mehr Code

(Im Idealfall versetzt du uns in die Lage, dein Programm hier bei uns zu 
komplieren, die Werte die du benutzt einzugeben und wir können hier bei 
uns den Fehler reproduzieren)


Welche Werte haben

   wert
   x2

Hast du die Werte überprüft oder denkst du nur, dass sie die Zahlen 
beinhalten?

Autor: dito (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
x2 wird  nirgendswo zugewiesen. Insofern sagt dein geposteter Code 
leider noch nichts aus.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ghd schrieb:
> hier noch der ganze Code.

Das ist aber mal ne bodenlose Übertreibung.

Außerdem erstmal das fettgedruckte über dem Postingfenster lesen !!!
(Formatierung bzw. Anhang).


Peter

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo

ja, wert kann 1400 -  2700 sein.

Kurze erklärung zu code.
Ein ziemlich unruhiger wert soll mit dieser Routine
ruhig gestellt werden. D.h. ein wert kommt rein (wert)
durch die ersten beiden If schleifen wird minimal und maximal wert
begrenzt. Anschließend enthät wert1 einen wert von 0-999.
x2 enthält den Wert der beim vorherigem Aufruf ausgegeben wurde.
Beträgt die Differenz zwischen dem alten und dem neuen Wert mehr
als 21 soll nicht so stark geschnitten werden damit sich der Wert
schnell ändert. Ist die Differenz dann kleiner als 21 wird stärker
geschnitten um den Wert ruhig zu bekommen. x2 enthält also immer den
alten Wert. Dieser gewichtet dann mit dem Faktor 9 und der neue Wert mit 
dem Faktor 1, das ganze geteilt durch 10 und der Wert ist schön ruhig.
Angenommen x2 wäre 900 und wert1 wäre 999, müsste nach 10 durchläufen
x_wert = 999 sein. Da aber nach der Multiplikation (x3 = x2*9) nur
8910 anstatt 8991 rauskommen ist der maximal wert von wert1 = 990.

Autor: Tropenhitze (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Füg doch 'mal folgende Zeile ein:
x = 999 * 9;
Und dann laß Dir das Ergebnis von x zeigen. Wenn 8991 'rauskommt, ist 
der Fehler nicht bei der Multiplikation zu suchen, sondern tunlichst 
woanders.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ghd schrieb:

> Angenommen x2 wäre 900 und wert1 wäre 999, müsste nach 10 durchläufen
> x_wert = 999 sein.

Angenommen ... müsste

Nicht annehmen. Hast du es kontrolliert? Hast du deinem Programm 
zugesehen, wie es rechnet?

> Da aber nach der Multiplikation (x3 = x2*9) nur
> 8910 anstatt 8991 rauskommen ist der maximal wert von wert1 = 990.

Du bist wie ein Arzt, du siehst dir die Smptome an und schliesst daraus 
auf die Ursache.
Du kannst das aber besser machen als ein Arzt. Sieh dir die 
Ausgangswerte und Zwischenergebnisse an! dann brauchst du nicht raten.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Stimmt, dann kommt 8991 raus.
Steh aber trotzdem auf dem schlauch. Habe schon alles mögliche
versucht und finde den Fehler nicht.

Autor: Dirk W. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Tropenhitze: Stimmt leider nicht: eine solche Anweisung wird vor dem 
Kompilieren bereits vom C-Präprozessor in "x = 8991" verkürzt (d.h. der 
PC multipliziert dann, nicht der µC)

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ghd schrieb:

> Habe schon alles mögliche versucht

Wohl kaum. Z.B. hast du immer noch keinen kompletten Testcode gepostet.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk W. schrieb:

> @Tropenhitze: Stimmt leider nicht: eine solche Anweisung wird vor dem
> Kompilieren bereits vom C-Präprozessor in "x = 8991" verkürzt

Nein. Schau es dir an (gcc -E).

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
wie, kein Testcode,

die Routine kann getestet werden!

Out(3000);

und  x_wert  anzeigen lassen.

dann müsste 999 rauskommen.

Autor: Yalu X. (yalu) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Angenommen x2 wäre 900 und wert1 wäre 999, müsste nach 10 durchläufen
> x_wert = 999 sein.

Das ist ein Trugschluss.

Du erwartest, dass x2 mit der zeit gegen x_wert=999 konvergiert, was
aber auf Grund von Rundungsfehlern der Integerdivision nicht passiert.
Bei x2=990 steigt der Wert nicht weiter, weil dann

  (9 * x2 + x_wert) / 10 = (9 * 990 + 999) / 10 = 990.9

ist, was auf 990 abgerundet wird. Damit ist das neue x2 gleich dem alten
x2. x2 kann also nie größer als 990 werden.

Autor: dito (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Poste doch einfach mal den Teil, wo x2 deklariert und initialiert wird 
(und ggf. alle nachfolgenden Zuweisungen). Genau da wird nämlich der 
Fehler liegen, weil x2 nun mal nicht 999 ist.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hoppla, das stimmt. Vielen Dank für den Hinweis.
Hm, das müsste dann aber mit float Variablen funktionieren.
Das Endergebniss dann einer int Variablen zuweisen. Oder liege
ich da falsch.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@dito

x2 wird folgendermaßen als Globale Variable deklariert.

unsigned int x2 = 0;

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ghd schrieb:
> wie, kein Testcode,
>
> die Routine kann getestet werden!

Kein main(), kein uebersetzbares Programm, kein reproduzierbarer Test.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
du kannst auch einfach das Teilen durch 10 lassen und alle konstanten 
mal 10 nehmen... dan kommt man ohne Float aus.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
puh, also ich weiß ja nicht, aber einfach einen Standard sheet
nehmen, die Routine einfügen und in der main den Aufruf.
Ein allgemeingültiges Programm für alle µC´s und Compiler zu schreiben
das einfach per drag & drop in den Compiler kopiert wird u.s.w wird 
schwer.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Läubi

Danke. Klar, werd ich so machen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ghd schrieb:
> puh, also ich weiß ja nicht, aber einfach einen Standard sheet
> nehmen, die Routine einfügen und in der main den Aufruf.
> Ein allgemeingültiges Programm für alle µC´s und Compiler zu schreiben
> das einfach per drag & drop in den Compiler kopiert wird u.s.w wird
> schwer.

Und woher sollen wir wissen, wie x2 definiert ist (ok hast du 
nachgereicht). Was ist mit

wrlcd_ziffK(0);
wrlcd_ziffK(1);
wrlcd_cmbuff(1);


wie ist cmd_buf definiert (auch dort könnte ja ein Fehler sitzen)

x2 ist eine globale Variable. Wer garantiert mir, dass nicht einer 
dieser Funktionsaufrufe diese Variable verändert. Wer garantiert mir, 
dass cmd_buf nicht zu klein definiert ist, und der itoa das x2 
niederbügelt?


Du willst Hilfe! Denkst du nicht, das es dann an dir liegt, alles so 
aufzubereiten, dass ich direkt Lust darauf habe, dein Programm einfach 
auszuprobieren. Wenn ich vorher auch noch 50 Syntaxfehler durch 
auskommentieren fixen muss und die Hälfte des Programms dazuerfinden 
muss, nur damit ich es erst mal durch den Compiler kriege, hab ich 
ehrlich gesagt keine allzugroße Lust, genau das zu tun.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@kbuchegg

oh mann,

wrlcd_ziffK(0);
wrlcd_ziffK(1);
wrlcd_cmbuff(1);

sind meine Display Routinen. Da passiert garantiert kein Fehler.
Der Fehler ist schon gefunden. Dank findiger Forumsmitglieder.
Danke.

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@kbuchegg

was für ein Compiler hast DU????
was für ein µC hast du?

mit diesen Angaben kann ich dir den Code nach deinen Wünschen
aufbereiten.
Aber wie gesagt. Das Problem ist schon behoben, dank Läubi und Yalu X. 
!!!
Danke nochmal.

Autor: Klaus Falser (kfalser)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
[OT]
Karl heinz Buchegger schrieb:
> Als Österreicher muss ich das nicht so genau wissen. Oder wusstest du
> wie sich der Herr Alfred Hrdlicka richtig schreibt :-)

Habe in Wien studiert, hätte es möglicherweise sogar gekonnt.
Lest ihr jetzt Jelinek statt Goethe im Österreichisch-Unterricht?
:-)
[/OT]

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Eine typische Glättung (RC-Tiefpaß) schreibt man besser so:

x_ausgabe = x_sum >> 4;
x_sum += x_messwert - x_ausgabe;

Dann konvergiert das Ergebnis auch.

Und rechnet sauschnell, da kein mul/div nötig.


Peter

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@peda

vielen Dank für den genialen Code.
Werde den gleichmal einbauen.

Gruß

Autor: Volker Zabe (vza)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Für extrem gestörte Signale habe ich mal folgendes benutzt:
x_temp = x_sum1 / 15;   // 15=3*5
x_sum1 += x_messwert - x_temp ;

x_ausgabe = x_sum2 / 14;   // 14=2*7
x_sum2 += temp - x_ausgabe;

Hat den Vorteil das (fast) alle Harmonischen der Abtastfrequenz 
unterdrückt werden. -> Primzahlen (2 3 5 7).

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@vza

Danke. Auch ganz nett. Werd´s mal versuchen.

Autor: Christian H. (netzwanze) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
BTW

ghd schrieb:
> durch die ersten beiden If schleifen wird minimal und maximal wert

Siehe http://www.if-schleife.de/

Autor: ghd (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Christian H. schrieb:
> BTW
>
> ghd schrieb:
>> durch die ersten beiden If schleifen wird minimal und maximal wert
>
> Siehe http://www.if-schleife.de/

hehe, ja ja, schon klar. Nette seite. Oh Gott, wer hat den die
Muse soetwas zu tun, ohmg.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.