mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Multiplikation führt zum falschen Ergebnis! Warum?


Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich arbeite gerade in meiner Diplomarbeit an einem Programmiergerät für 
einen Winkelsensor. Ich benutze dabei einen AVR mega8. Bei der 
Berechnung einiger Werte habe ich unter anderem folgendes
unsigned long int a = 0;    // maximal 2^32 - 1 = 4.294.967.295
  unsigned long int b = 0;
  unsigned long int c = 0;

  calc_ang_rng_mult = ((1000 * (unsigned long int)ang_rng_mult) / 16384);    // = 524.287.000 / 16.384 = 31.999,...

  a = (((unsigned long int)(clamp_hi - clamp_lo) * 100000) / 8192);      // = 460.700.000 / 8.192 = 56.237,...
  b = ((180 * 10000000) / calc_ang_rng_mult);                  // = 1.800.000.000 / 31.999 = 56251,...
  c = ((unsigned int)a * (unsigned int)b);                  // = 56.251 * 31.999 = 1.799.975.749
  calc_ang_rng = (c / 100000);

Die dezimalen Maximalwerte habe ich jeweils als Kommentar in den Code 
eingefügt. Die Variablen calc_ang_rng_mult, a und b werden richtig 
berechnet. Die Werte stimmen mit dem überein, was als Kommentar in der 
jeweiligen Zeile steht. Variable c erhält jedoch nicht den Wert 
1.799.975.749 sondern nur 30.303. Warum ist das so? 1.799.975.749 müsste 
ich doch in einer unsigned long int Variable darstellen können.

Für Hinweise oder Erklärungen wäre ich sehr dankbar! Wie das immer so 
ist bei Diplomarbeiten: Die Zeit rennt...

Grüße,
Daniel

Autor: Ralf (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> unsigned long int a = 0;
??? Ich dachte, es gibt entweder LONG oder INT, aber nicht beides 
zusammen?

> c = ((unsigned int)a * (unsigned int)b);
Wenn du auf explizit auf INT castest, kommt dann nicht auch ein INT 
raus? Muss mal mein C-Buch rausholen, hab's grad nicht hier.

Ralf

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ralf wrote:

> ??? Ich dachte, es gibt entweder LONG oder INT, aber nicht beides
> zusammen?

Offiziell heisst das "long int" und "short int", aber man darf das "int" 
weglassen.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mir den Kram jetzt nicht im Detail angesehen, es gab aber eine 
WinAVR Version, die mit "long" Multiplikation auf Kriegsfuss stand. 
4.3.0 von April/Mai oder so. Auch manche Version aus debian und Ubuntu.

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Danke für die schnelle Antwort. Ja, die Typumwandlung (unsigned int)a 
bzw. b habe ich nachträglich als Versuch mal mit dort reingebracht. Wenn 
ich es weglasse, dann steht in c der Wert 3.163.387.487 - das ist 
immerhin was anderes, aber der µC hat sich immer noch verrechnet :-)

Grüße,
Daniel

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich habe die letzte offizielle WinAVR-Version, Release 20081205 
installiert.

Den Vorschlag von Michael habe ich ausprobiert:
c = ((unsigned long int)a * (unsigned int)b);

Das Ergebnis ist wieder 3.163.387.487...

Grüße,
Daniel

PS: Wahnsinn, wie schnell hier die Antworten kommen! Vielen Dank!

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist ja auch richtig! Schau mal in Deine Kommentarzeilen  wo a= und b= 
vorne stehen (ich sehe da keine 31.999)!?

Autor: Michael K. (mmike)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Versuch mal die Datentypen aus der <inttypes.h> in Deinem Fall also 
uint32_t.
Und lass die Typecasts mal bei der Multiplikation weg ...

also:
uint32_t a = 0;    // maximal 2^32 - 1 = 4.294.967.295
uint32_t b = 0;
uint32_t c = 0;

calc_ang_rng_mult = ((1000 * (uint32_t)ang_rng_mult) / 16384);
a = (((uint32_t)(clamp_hi - clamp_lo) * 100000) / 8192);
b = ((180 * 10000000) / calc_ang_rng_mult);
c = (a * b);
calc_ang_rng = (c / 100000);

Grüße,
Michael

Autor: Route_66 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
jedenfalls nicht als Ergebnis (vielleicht besser 56.237)

Autor: Artem G. (jorjo)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

Versuch mal vielleicht "c=a*b;" zu schreiben;
weil "c" vom gleichen Typ wie a und b ist

Mfg
Artem

Autor: Daniel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Route_66 hat völlig recht! Ich bin ein Trottel und sehe den Wald vor 
lauter Bäumen nicht mehr... Das Ergebnis stimmt ja auch - die 
Kommentarzeile ist falsch!

Ich danke auch trotzdem! Wir ist einiges klar geworden bezüglich den 
evtl. notwendigen Typumwandlungen bei Multiplikation. War also nicht 
völlig umsonst!

Dankeschön,
Daniel

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.