www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Division großer Integerzahlen


Autor: Toellner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich möchte folgende Berchnung möglichst genau durchführen.
Wichtig es gehen nur Integer bzw. Unsigned Integer Zahlen.

uint_Input = 32786        //Input kann zwischen 5190...61047 liegen

uint_Dmin = (5190);
uint_Dmax = (61047);

// Meine gewünschte Berechnung:
uint_Output = (uint_Input-uint_Dmin)/(uint_Dmax-uint_Dmin)*65535

Ich weis das ich die Berechnung in mehrere Einzelberechnungen 
unterteilen muss und auch irgendwie mit Modulo (%) rechnen muss. Aber 
wie der genaue Algorithmus aussieht um ein möglichst Ergebnis zu 
erhalten.

Ich hoffe mir kann das jemand erklären.
Danke schon im Vorraus!!!

Autor: Matthias (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
na zuerst mal beide Differenzen getrennt errechnen..
PS: wäre es nicht sinnvoller, mit 65536, statt 65535 zu multiplizieren??
Weil dann könntest jetzt
die Division durchführen (siehe Anhang)
und die Mult. mit 65536 = 2^16 kannst dir sparen,
weil du das ganze nur um zwei Byte nach links schiebst...

und modulo brauchst hier nicht...

Autor: Toellner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, Multiplikation mit 65536 ist Richtig (war falsch von mir)

Also:

uint_temp1 = uint_Input - uint_Dmin

uint_temp2 = uint_Dmax-uint_Dmin

uint_Output = uint_temp1/uint_temp1 -> ???
                                    -> avr200.asm
                                    -> Ich habe zwar momentan einen AVR 
zum Testen das ganze soll später auf einen Freescale MC ;(
Gibt es ne andere (C-)Lösung?

Aber schon mal Danke!

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
in C kannst du ruhig das schreiben:
uint_Output = ( (uint_Input-uint_Dmin)/(uint_Dmax-uint_Dmin) ) << 16 );

Wobei, wie gesagt, lass das schieben um 16bit, oder mult. mit 65536 
einfach weg, und mach nur:
uint_Output = (uint_Input-uint_Dmin)/(uint_Dmax-uint_Dmin)
und "denke" dir die zwei nullen einfach hinten dran..

alternativ:
uint_temp1 = uint_Input - uint_Dmin
uint_temp2 = uint_Dmax-uint_Dmin
uint_Output = uint_temp1/uint_temp1



Oder was meinst jetzt?

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Freescale MC

Sollten die mit 32-Bit-Zahlen nicht sowieso zurechtkommen?

Assembler (AVR 200 umgesetzt):
Beitrag "DIVISION 32 BIT / 32BIT Beispiel (Assembler) ATmega8"

in C:
Beitrag "Re: Zahlenausgabe"

Autor: Rahul, der Trollige (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was vergessen:
Es ist natürlich sinnvoll, erst mit 65536 zu multiplizieren und dann zu 
dividieren. Da kommt dann vermutlich etwas mehr raus...

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

Bewertung
0 lesenswert
nicht lesenswert
> und "denke" dir die zwei nullen einfach hinten dran..

Wieso 2 Nullen. Hex vielleicht, aber dezimal sind
da keine 2 Nullen.

Als erstes:
* Grundregel: Divisionen schiebt man in der Verarbeitungs-
  kette soweit nach rechts wie möglich.

  uint_Output = ( (uint_Input-uint_Dmin)/(uint_Dmax-uint_Dmin) ) << 16 );
Wenn die Division schon 0 ergeben hat, kannst du nach links
schieben soviel du willst, das bleibt trotzdem 0.

Also Divisionen nach hinten:
Aus
  uint_Output = (uint_Input-uint_Dmin)/(uint_Dmax-uint_Dmin)*65536
wird
  uint_Output = (uint_Input-uint_Dmin)*65536/(uint_Dmax-uint_Dmin)

Wobei sich jetzt natürlich das Problem ergibt, dass die
Multiplikation in int, bzw. unsigned int gemacht wird und
somit einen Overflow produzieren kann. Um das zu vermeiden
stellen wir erst mal sicher, dass die Multiplikation
als long Multiplikation durchgeführt wird.

  uint_Output = (uint_Input-uint_Dmin)*65536UL/(uint_Dmax-uint_Dmin)

Bei einer Berechnung werden immer beide beteiligte Operanden
auf gleiche Datentypen gebracht. Ist einer der beiden long, wird
auch der andere zu long und die Operation wird dann als long
Operation durchgeführt. 65536UL ist ein long (genauer:
ein unsigned long), ergo: die Multiplikation wird komplett
in unsigned long durchgeführt und das Ergebnis ist ebenfalls
ein unsigned long.


Somit sind Overflows soweit gebannt.

Ach ja. Das Schieben um 16 Bit anstatt der Multiplkation.
Diese Optimierung überlassen wir besser dem Compiler. Das
können die seit 30 Jahren zuverlässig.


Autor: Mark Toellner (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Karl Heinz,

ich habe es heute nach deiner Vorabe mit Long umgesetzt. Es funktioniert 
prima! :)

Danke an alle Helfer!

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.