www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Kommastelle


Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo zusammen
Mit meinem ATMega8515 führe ich in Assembler einige Rechnungen durch.
Unter anderem muss ich eine Zahl durch 5 teilen.
Die Zahl kann zwischen -20 und +20 liegen und ist ganzzahlig.

Kann mir jemand einen Tipp geben wie man das teilen durch 5 am
geschicktesten realisiert?
Wie wird denn dann die Nachkommastelle welche entsteht berücksichtit?

Beispiel:
9/5=1,8
Das Ergebnis möchte ich nun gerne weiterverwenden bzw. auf einem
Display anzeigen.
Wie geh ich mit diesen Kommazahlen um?

Vielen Dank schonmal für eure Hilfe!

Autor: MasterFX (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Am besten geht das mit fixedpoint-Format:
(x*10)/5
Dann hast du im Ergebnis die letzte Stelle als Nachkommastelle, du
musst also nur das Komma an der richtigen Stelle einfügen bei der
Ausgabe.
Das kannst du natürlich gerade kürzen zu
x*2
was nochmal eine schöne Ersparnis bringt, da das nur ein reiner
linksshift ist.
Ergo: Ein einziger Takt benötigt. Für eine echte Division bist du
locker 50 los...

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sind -20 und +20 durchweg ganze Zahlen?
Dann könnte man einfach die ganzzahlige Division mit Rest durchführen.
Der Rest kann dann nur Werte zwischen 0 und 4 annehmen (Nachkommastelle
wären dann 0/5=0, 1/5= 0,2, 2/5=0,4, 3/5=0,6 und 4/5=0,8).
Die müsste man bei der Anzeige nur noch "hinzuaddieren" / mit
anzeigen.
Bei Kommazahlen müsste man die Zahl entsprechend der gewünschten
Nachkommastellen erweitern und dann das Ergebnis wieder um den Faktor
teilen....

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die einfache Antwort lautet:
Besorg dir eine Fliesskomm-Arithmetik-Bibliothek und
dein Problem ist gelöst. Dafür öffnet sich ein neuer
Sack von Problemen.

Die pragmatische Lösung lautet:
Gar nicht. Die meisten µC unterstützen von Haus aus
nur Ganzzahlen. Da es bei deinem µC so ist, wirst du mit
den ganzen Zahlen alleine auskommen müssen.

Die praktische Antwort lautet:
Wieviele Nachkommastellen willst du den?
Eine. Oh das ist leicht

 ( 9 * 10 ) / 5 = 18

und bei der Ausgabe schmuggelst du zwischen Zeher- und Einer-
stelle ein Komma hinein.

Im Ernst: Das Zauberwort heist meistens Fixed-Point-Arithmetik
Die Idee dahinter ist einfach alle Berechnungen mit einem
ganzzahligen Vielfachen zu machen. Wie im obigen Beispiel:
Alles mal 10 und sich merken, dass da ein Komma vor der
letzten Stelle sein muss.
Die Idee ist an sich nicht neu, du machst das mit Sicherheit
schon seit Jahren so. Rechnen wir doch mal:

  2 Euro 50  +  3 Euro 20

also  2.50 + 3.20  ergibt 5.70

Das kann man so rechnen, muss man aber nicht. Man kann anstelle
von Euros ganz einfach auch in Cent rechnen

    250 + 320  ergibt 570

und bei der Ausgabe schmuggelt man ein Komma vor die Zehnerstelle

    5 Euro 70

Wenn 2 Nachkommastellen nicht reichen, dann geht man halt
auf 1/10 Cent oder 1/100 Cent als Basiseinheit.

Das funktioniert solange gut, solange alles in einen der vorhandenen
Ganzzahltypen passt und die Wertebereiche alle in etwa gleich
sind: Wenn ich die Entfernung zum Mars in Atomdurchmessern
ausdrücken möchte, dann wird das nicht wirklich gut funktionieren.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
:-)

Ja es sind immer Ganzzahlen also werd ich es mit der
Fixed-Point-Arithmetik machen.

Vielen Dank mal.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Achso eins noch :-)

Wie geh ich denn am besten mit negative Zahlen um?
Beispiel:
-9/5= -1,8

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Vorschlag:
Prüfen ob die Zahl negativ ist, wenn ja, dann Zweierkomplement bilden
und merken, dass es sich um eine negative Zahl handelt.
Dann die Division berechnen.
Und dann bei Bedarf wieder zurückwandeln.

Bestimmt findet man sonst auch irgendwo "Berechnungsregeln" für
sowas... (Andreas Roth hat das "Mikrocontroller Applikations
Kochbuch" mit solchen Sachen gefüllt...)

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also quasi schauen ob es negativ ist, positiv rechnen und nachher wieder
ein Minus "hinschmuggeln" !?

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
genau

Autor: Rahul (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann aber auch sein, dass das noch einfacher geht...

Autor: Christoph Kessler (db1uq) (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
In einer Tabelle nachzuschlagen wäre bei dem kleinen Wertebereich auch
zu überlegen, ist auf jeden Fall die schnellste Berechnung.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Frage ist ob du im Resultat den Bruchteil/Kommastelle auch benötigst
und anzeigen möchtest, oder ob du wiederum eine gerundete Ganzzahl haben
möchtest. Falls zweites zutrifft dann einfach (X + (5-1)) / 5 rechnen.

Gruß Hagen

Autor: arc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
n/5 = n * 0.2, 0.2 passend skalieren z.B. 20
ergibt für -20 -> -400 = -4.0 und für z.B. 9 -> 180 = 1.8
Falls man keine Multiplikation hat x = n <<= 4 + n << = 2

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@arc, ja das ist nichts anderes als Fixkomma Rechnung ;)
Würdest du mit 2^x skalieren (statt 100) dann stände dieses Festkomma
an x'ter Stelle, so steht es an 10^2'ter Stelle.

Gruß Hagen

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne als Ergebnis brauch ich schon die Kommastelle.
Also als Beispielwert soll 2,2 angezeigt werden.

Autor: arc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie soll aus einer geraden Zahl (2^x) und 1/5 eine ganze Zahl werden.
Bsp. 0.2 * 256 = 51.2 und diese 51.2 müssten immernoch * 10 genommen
werden um "genau" zu sein.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gegenfrage wie willst du 10*100 / 3 auf diese Weise exakt berechnen ?

Fakt ist: ob du mit 100 skalierst oder mit 2^x spielt mathematisch
gesehen keine Rolle. Beides ist eine Skalierung zum Zwecke einer
Fixpoint Berechnung, nur die Zahlen Basis ist unterschiedlich.

Klar, eine Skalierung mit 100 hätte den Vorteil das wir damit besser
umgehen können und in der eventuellen späteren Anzeige einiges
einfacher würde. Aber das ist kein Argument pro Basis 10^x denn intern
sind alle Zahlen sowieso 2'er Potenzen. Wir müssen also für die
Anzeige in beiden Fällen eine Umrechnung in einen String vornehmen. Ob
diese Umrechnung nun einen String formatiert zur Basis 10 oder 2 oder
16 (HEX) erledigt ist dabei irrelevant.

Die Berechnungen einer Fixpoint Zahl zur Basis 2 sind dagegen
wesentlich einfacher. Zb. eine Division durch 2^x ist immer ein
Rechtsshift mit anschließender Fixpoint Korrektur. Bei der Basis 10
müssen wir diese Operation immer mit vollständigen Divisonen und
Multiplikationen durchführen. Die Basis 2 ist also weit besser geeigent
für schnelleren Code.

Das math. Resultat ist aber bei beiden identisch, mal abgeshen von der
Wertmäßigen Auflösung der Berechnungen, sprich den Genauigkeiten.

Gruß Hagen

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Beipsiel:

Basis ist 2^8 = 256. Also steht unser Fixpoint immer bei Bit 8, das
unterste Byte = LSB stellt also die Nachkomastellen dar, die Bruchteile
von x * 1/256.

Eine Anzeige dieser Zahl kann nun sehr effizient Downscalen. Man
betrachtet nur die MSB's ansich und hat den Vorkommateil als Ganzzahl.
Die Nachkommastellen stehen im LSB drinnen. Runden ist ganz einfach
indem man checkt ob LSB >= 128 ist und dann MSB +1 rechnet.

Wie aber zu Basis 10^x ?

Wir wollen runden und müssen erstmal unsere Zahl durch 10^x dividieren
um den Vorkommateil und die Nachkommastellen als Rest zu bekommen.

Also tricksen wir indem wir vor dieser Division exakt 10^x / 2 auf
unsere Zahl addieren und erst danach durch 10^x dividieren. In jedem
Falle müssen wir aufwendig dividieren und das ist jua bekanntlich auf
dem AVR ein zeitraubender Prozess.

Wenn wir mit 10^2 = 100 skalieren dann haben wir eine AGenauigkeit in
den Nachkomastellen von 100, sprich 100 verschiedene Werte kann die
Nachkomastelle annehmen, sprich 1/100'tel

Skalieren wie mit 2^8 = 256 dann haben wir eine Genauigkeit von 256
Werten sprich 1/256'tel. Zusätzlich ab den Vorteil das wir direkt die
Kommastelle im binärcode unserer Zahlen haben, also nicht nur
mathematisch betrachtet sondern auch technisch gesehen. Wir können nun
das LSB als Nachkommastelle ansprechen.

Nunja: ob Fixpoint oder Fließkomma, man benutzt idealerweise immer ein
Skalierung mit 2^x.

Gruß Hagen

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

die von Jan und Karl Heinz vorgeschlagene Lösung ist ne
Milchmädchenrechnung. Die Lösung von 9/5 war demnach 9*2=18 und nen
Komma bei der Ausgabe reinschmuggeln. Wer macht denn die Ausgabe,
printf() ?! Zitat Hagen: 'denn intern sind alle Zahlen sowieso 2'er
Potenzen'. Die '18' oder hexadecimal 0x12 muß dann von printf()
durch 10 geteilt werden, damit ist die Division drin und das ganze
printf-Zeuchs.

So machen:
for(k=0;k<=20;k++) {
 m=k;i=0;
 while(m>4){m-=5;i++;}
 printf("%.1f %c.%c\n",k/5.0,i+'0',(m<<1)+'0');
}

Cheers
Detlef

PS: Das ist eigentlich keine Milchmädchenrechnung, sondern eine
Managerrechnung, weil die Division an printf() delegiert wird, und
delegieren ist ja die Schlüsselqualifikation des Managers.

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
;)

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Wer macht denn die Ausgabe, printf()

Hmmm... - Im ersten Posting war aber von Assembler die Rede, da gibt es
kein printf()

Meine Eigenbau-LCD-Routinen haben sehr wohl die Möglichkeit, ein Komma
an einer bestimmbaren Position (n. Stelle von rechts) einzuschmuggeln.
Somit bietet sich das Skalieren um Zehnerpotenzen an.

...

Autor: Jan M. (mueschel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Und selbst wenn man printf verwenden will, geht das einfach. Man darf
mit dem "vorkauen" für den Compiler nur nicht einfach mittendrin
aufhören, sondern das ganze konsequent durchziehen.
Zahl mit itoa() in einen String umwandeln, dort zwischen erstem und
zweiten Zeichen ein Komma einfügen, Ausgabe mit printf.
Wieviel Zeit das dann wirklich noch einspart, bleibt dahingestellt,
aber zum Einen war danach nicht gefragt und zum Anderen widersprechen
sich die beiden Themen "Laufzeitoptimierung" und "Ausgabe mit
printf".
Klar, printf ist ein mächtiges Werkzeug, aber in 95% der Fälle völlig
übertrieben. (Hat mal einer 'nen Presslufthammer? Müsste ma' schnell
zwei Eier für den Kuchen aufschlagen...)

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Hmmm... - Im ersten Posting war aber von Assembler die Rede, da >>gibt
es kein printf()

genau, deswegen bringt die Rechnung 9*2=18=0x12 nix. Zur 'händischen'
Darstellung ohne Benutzung von printf() muß du 0x12 durch 10 teilen.

>> Zahl mit itoa() in einen String umwandeln,

Das Dividieren durch 10 muß iota auch machen.

Bei dem gewünschten Zahlenbereich geht das mit dem Beispielcode.

Cheers
Detlef

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Das Dividieren durch 10 muß iota auch machen.

Wenn man binäre Zahlen als ASCII-String mit Ziffern in
Dezimalschreibweise ausgeben will, dann wird man um das Teilen durch 10
(100, 1000...) sowiso nicht herum kommen. Das war aber sicherlich nicht
das Problem...

...

Autor: Detlef _a (detlef_a)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Das war aber sicherlich nicht das Problem...

Nee, das Problem war durch 5 zu teilen, jetzt vermeidet man das und
muss durch 10 teilen, Thorsten will das Ergebnis anzeigen!

Wird Zeit, daß die Gentechniker aus den Pantoffeln kommen und
standartmäßig 8 Finger an jeder Hand möglich machen um dem
Dezimalsystem den Todesstoß zu versetzen.

Cheers
Detlef

Autor: Hannes Lux (hannes)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Nee, das Problem war durch 5 zu teilen, jetzt vermeidet man das und
> muss durch 10 teilen, Thorsten will das Ergebnis anzeigen!

Man muss (in der Ausgaberoutine) sowiso durch 10 teilen, wenn man die
(binäre) Zahl dezimal anzeigen will. Das Teilen durch 5 war eine
zusätzliche Berechnung, die nichts mit der sowiso erforderlichen
Integer-ASCII-(String)-Konvertierung zu tun hat. Diese lässt sich im
konkreten Fall durch das Skalieren mit 10 einsparen, was durch Anzeigen
der letzten Stelle als dezimale Nachkommastelle kompensiert wird. Dazu
muss allerdings die (ASM-) Ausgaberoutine über die Möglichkeit des
Einfügens eines Dezimaltrennzeichens (Punkt, Komma) an eine
definierbare Position verfügen. Da man in ASM seinen Code selbst
schreibt und nicht auf irgendwelche Bibliotheken bzw. Funktionen
zurückgreift, ist das aber kein Problem.

...

Autor: Hagen Re (hagen)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>>Wird Zeit, daß die Gentechniker aus den Pantoffeln kommen und
>>standartmäßig 8 Finger an jeder Hand möglich machen um dem
>>Dezimalsystem den Todesstoß zu versetzen.

Du wirst es kaum glauben aber 30 Finger sind noch besser. Denn das ist
2*3*5 und enthält somit alle kleinen Faktoren. Es ist direkt kompatibel
zu jedem Zahlensystem <= 30 das sich aus diesen Faktoren ergäbe, also
2,3,4,5,6,8,9,10,12,15,16,18,20,usw. usw.

Und ein guter Freund von mir (Mathematiker und Statistiker) rechnet
sogar real mit solchen Zahlen im Kopf, verrückt.

Sorry für OT.

Gruß Hagen

Autor: arc (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Fractional/Fixpoint-Format gab's schon mal...
z.B. http://www.mikrocontroller.net/forum/read-10-353356.html
und ist in diesem Fall absoluter Overkill, da nur eine Nachkommastelle
rauskommt. Eine Multiplikation mit 2 würde also reichen (zum runden
+5).

"Es gibt nicht nur Vorschlaghämmer"

p.s. diese Zahlensysteme sind eigentlich nur sinnvoll, wenn man
Primzahlen im Kopf bestimmen will, die ökonomischte (ganzzahlige) Basis
ist 3, ansonsten e.

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hmm da hab ich ja ne ganz nette Diskussion angeregt :-)
Vielen Dank jedenfalls für eure Hilfe!

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.