Torsten C. schrieb:> In C# gibt's dafür ja System::Decimal. In C nicht, oder?
Hab keine Ahnung von C#. Da die Darstellung der Möglichen
Nachkommastellen (bzw. auch die Abschneidung von Bits) ja auch nichts
mit der Programmiersprache zu tun hat, ist das doch auch egal. Wichtig
für's Verständnis ist halt, dass nicht beliebig viele Bits behandelt
werden können - dabei spielt es auch keine Rolle, ob Soft- oder
Hard-FPU. Oder habe ich einen Denkfehler? - ist noch früh :-)
Ja.
Oder bei MCUs gänzlich auf Gleitkommazahlen verzichten, geht auch:
http://www.mikrocontroller.net/articles/Festkommaarithmetik
Solche Berechnungen können - ohne FPU - den Programmcode nämlich ganz
schön aufblähen und langsam machen.
Gerade die Kommazahlen mit n/10tel als Nachkomma-Stelle sind binär nie
exakt darstellbar. Die Nachkommastellen bei Binärzahlen haben die
Wertigkeiten 2^-1, 2^-2 usw. 1/10 (als Beispiel) ist aber 1/(2*5) und
die Primzahl 5 im Nenner ergibt in Binärdarstellung eine periodische
Zahl.
Wer mal ein Gefühl für die Zahlendarstellung bekommen will, kann ja mal
unter http://www.h-schmidt.net/FloatConverter/IEEE754de.html etwas
experimentieren.
Dieser Effekt ist sogar bei manchen Taschenrechnern zu beobachten.
Gib mal ein: 1 ÷ 3 = × 3 =
Das Ergebnis sollte wieder 1 sein, manche Taschenrechner zeigen jedoch
0.99999999 an.
Tutnichtszursache schrieb:> Oder bei MCUs gänzlich auf Gleitkommazahlen verzichten, geht auch:> http://www.mikrocontroller.net/articles/Festkommaarithmetik
Nein, nein, nein!
Wichtig ist eher, solange 'float' weiterzurechnen, bis eine gerundete
Ausgabe notwendig wird.
> Solche Berechnungen können - ohne FPU - den Programmcode nämlich ganz> schön aufblähen und langsam machen.
Und nochmals für allgemeine Anwendungen: Nein!
m.n. schrieb:>> Solche Berechnungen können - ohne FPU - den Programmcode nämlich ganz>> schön aufblähen und langsam machen.>> Und nochmals für allgemeine Anwendungen: Nein!
Das kriegst du ebenso wenig wieder aus der Welt geschafft wie die
beliebte VCC Verbindung an AREF. ;-)
Das hilft dir nichts, wenn du das Ergebnis vom round dann wieder an
einen float zuweist.
Der entscheidende Punkt ist, dass du bei der Umwandlung in einen int
runden musst. Damit aus 30029.99999999 dann eben 30030 wird und nicht
durch abschneiden der Kommastellen 30029.
Denn was machst du bei
1
zwischenwert_float=300.304;
2
zwischenwert_float=round(zwischenwert_float*100);
Das Ergebnis sollte eigentlich 30030.4 sein. Durch dein Runden wird es
aber zu 30030.0. Wenn du mit dieser float Zahl noch weiterrechnen muss,
dann ist das ein signifikanter Fehler.
-> Die Rundung willst du soweit nach hinten schieben wie nur möglich. In
deinem Fall erst bei der Umwandlung nach int.
Karl Heinz schrieb:> Das hilft dir nichts, wenn du das Ergebnis vom round dann wieder an> einen float zuweist.
Ganzzahlen sind als Fliesskommawert exakt darstellbar, so lange die
Stellenzahl der Mantisse ausreicht. Es kommt also darauf an, was man
erreichen will. Wenn die Multiplikation mit 100 den Sinn hat, 2
Nachkommastellen darzustellen, dann geht das.
A. K. schrieb:> Karl Heinz schrieb:>> Das hilft dir nichts, wenn du das Ergebnis vom round dann wieder an>> einen float zuweist.>> Doch, denn Ganzzahlen sind als Fliesskommawert exakt darstellbar, so> lange die Stellenzahl der Mantisse ausreicht.
Ich hab meinen Post noch mal geändert, weil ich eine schwache
Begründung hatte.
m.n. schrieb:> Nein, nein, nein!> Wichtig ist eher, solange 'float' weiterzurechnen, bis eine gerundete> Ausgabe notwendig wird.
Hi!
Ich habe das anders gelernt. Sobald eben keine FPU vorhanden ist, muss
das Berechnen von Gleitkommazahlen ja softwareseitig umgesetzt werden.
Ich dachte immer, das sei sehr rechenintensiv und benötigt viel
Speicher. Werde heute Abend mal ein paar Tests machen (float vs
hochgerechnete Integer) und mir selber ein Bild davon machen. Danke für
den Hinweis.
Dass die Ausgabe eines floats durch zusätzliche Bibliotheken den
Speicher dann noch zusätzlich aufbläht, ist ja klar.
Tutnichtszursache schrieb:> Ich habe das anders gelernt. Sobald eben keine FPU vorhanden ist, muss> das Berechnen von Gleitkommazahlen ja softwareseitig umgesetzt werden.> Ich dachte immer, das sei sehr rechenintensiv und benötigt viel> Speicher.
Wobei "viel" bei einem Zwerg mit 4KB ROM anders zu bewerten ist als bei
einem normalen Controller mit 64KB ROM.
Teuer ist printf und scanf mit Fliesskommaunterstützung, die man aber
leichter vermeiden kann als komplette bereits in Fliesskommaformeln
vorhandene Rechnungen. Die recht gut optimierten Laufzeitfunktionen
hingegen sind bei AVRs nicht so teuer.
Die Gegenrechnung zum etwas höheren Laufzeitaufwand gegenüber
Festkommaarithmetik ist der Zusatzaufwand bei der Programmierung.
Folglich ist es eine Einzelfallentscheidung, auf welche Art man rechnet.
Von einer ehernen Regel, Fliesskommarechnung sei "bäh" wenn keine FPU
vorhanden ist, halte ich nichts.
Tutnichtszursache schrieb:> m.n. schrieb:>> Nein, nein, nein!>> Wichtig ist eher, solange 'float' weiterzurechnen, bis eine gerundete>> Ausgabe notwendig wird.>> Hi!> Ich habe das anders gelernt. Sobald eben keine FPU vorhanden ist, muss> das Berechnen von Gleitkommazahlen ja softwareseitig umgesetzt werden.> Ich dachte immer, das sei sehr rechenintensiv
definiere 'sehr rechenintensiv'.
Wenn die Aufgabe darin besteht, alle 2 Sekunden den Messwert eines
DS18B20 als Temperatur auf einem LCD darzustellen und sonst nichts, dann
hat der µC alle Zeit der Welt, dies zu tun. Es ist überhaupt kein
Problem das in float zu rechnen. Selbst wenn du die Temperatur 10 mal
pro Sekunde benötigen würdest, wäre das noch rein von der Berechnung her
kein Problem.
> und benötigt viel> Speicher.
Für nicht benutzten Speicher gibt es kein Geld zurück.
generell ist die Zeit des Programmierers teurer als der nächst größere
µC. Für das Geld, dass 8K Flash mehr kosten, kann ich gerade mal ein
paar Sekunden arbeiten.
-> hüte dich vor verallgemeinerten Aussagen. Es gibt nur sehr wenige
Regeln in der Informatik, die wirklich universell gültig sind. Die
meisten sind aufzufassen als: "Im Prinzip: ja. Es gibt aber auch
Ausnahmen. 'One size fits all' funktioniert bei Baseballkappen, aber
nicht in der Softwareentwicklung.". Was nicht heisst, dass man sich an
gar keine Regeln halten soll. Die meisten Regeln haben schon ihren Sinn.
Sie sind aber mehr als Richtlinien zu verstehen. Wenn du aber einen Satz
von Regeln haben willst, an die du dich nur dogmatisch halten musst und
alles ist gut, dann bist du bei Religionen besser aufgehoben.
Karl Heinz schrieb:> generell ist die Zeit des Programmierers teurer als der nächst größere> µC. Für das Geld, dass 8K Flash mehr kosten, kann ich gerade mal ein> paar Sekunden arbeiten.
und was ist wenn mal 10.000 µC programmiert?
Karl Heinz schrieb:> 'One size fits all' funktioniert bei Baseballkappen,
Bei denen auch nicht. ;-)
Peter II schrieb:> und was ist wenn mal 10.000 µC programmiert?
Deshalb ja Einzelfallentscheidung.
Peter II schrieb:> Karl Heinz schrieb:>> generell ist die Zeit des Programmierers teurer als der nächst größere>> µC. Für das Geld, dass 8K Flash mehr kosten, kann ich gerade mal ein>> paar Sekunden arbeiten.>> und was ist wenn mal 10.000 µC programmiert?
10-tausend Sekunden sind auch erst knapp unter 3 Stunden.
Karl Heinz schrieb:> Peter II schrieb:>> Karl Heinz schrieb:>>> generell ist die Zeit des Programmierers teurer als der nächst größere>>> µC. Für das Geld, dass 8K Flash mehr kosten, kann ich gerade mal ein>>> paar Sekunden arbeiten.>>>> und was ist wenn mal 10.000 µC programmiert?>> 10-tausend Sekunden sind auch erst knapp unter 3 Stunden.
Ich hab mal einen 3D-Hidden Line Algorithmus auf einem PC-AT
geschrieben. Das war so um 1987/88 rum. Um auf Speed zu kommen, hab ich
ihn in Integer mit Festkommaarithmetik geschrieben. In Summe bin ich da
gut und gerne ein paar Monate verteilt auf ein 3/4 Jahr gesessen, bis
ich die Fix-Komma Konstanten soweit angepasst hatte, dass ich den
Kompromiss aus Auflösung und möglichst kleinem Datentyp abschnittweise
soweit im Griff hatte, dass er zufriedenstellend funktioniert hat. Klar,
bei einem 386 war das notwendig. Integer haben die Floating Point
Rechnungen ganz klar abgehängt und es war damals wichtig, dass das
schnell lief. FPUs waren damals noch nicht verbreitet.
Ein paar Jahre später kamen die 486 mit eingebauter FPU auf den Markt.
Das ganze neu geschrieben, diesmal mit double und nach ein paar Tagen
lief es problemlos.
Ok, ist voll und ganz verständlich, was ihr meint :-)
An die Optimierung der Arbeitszeit hab ich dabei wirklich nicht gedacht.
Da ich persönlich oft und gerne mit kleineren Mikrocontrollern arbeite,
liegt darin vermutlich der Grund zur Speicheroptimierung. Aber klar, ihr
habt vollkommen recht, dass die ganzen Umrechnungen ebenfalls zu mehr
Speicherverbrauch führen.
Wie gesagt, ich werde es heute Abend einmal genauer austesten und in
Zukunft dann wohl doch nicht mehr so float-feindlich sein. Kommt
natürlich auch darauf an, wie oft man im Code dann Berechnungen
durchführt.
Danke für eure Erklärungen bzw. Hinweise!
Tutnichtszursache schrieb:> wohl doch nicht mehr so float-feindlich sein. Kommt
Wobei man auch sagen muss, dass Floating Point auch nicht die Lösung
aller Probleme ist. Sie hat auch ihre Tücken. Vor allen Dingen dann,
wenn Fehlerfortpflanzung über viele Berechnungen hin ins Spiel kommt,
wie auch aus leidvoller und peinlicher Erfahrung lernen musste.
A. K. schrieb:> m.n. schrieb:>>> Solche Berechnungen können - ohne FPU - den Programmcode nämlich ganz>>> schön aufblähen und langsam machen.>>>> Und nochmals für allgemeine Anwendungen: Nein!>> Das kriegst du ebenso wenig wieder aus der Welt geschafft wie die> beliebte VCC Verbindung an AREF. ;-)
Aber ab und zu kann eine Seele gerettet werden ;-)
Tutnichtszursache schrieb:> Werde heute Abend mal ein paar Tests machen (float vs> hochgerechnete Integer) und mir selber ein Bild davon machen.
Das ist sehr löblich!
Zu AVRs: als diese noch keine MUL-Befehle hatten, waren die
Multiplikation für int32 und float fast gleich. Bei float müssen nur 24
Bit Mantisse gerechnet werden, dafür braucht die Anpassung des
Exponenten ein paar Takte zusätzlich.
Bei Division gibt es keine DIV-Befehle, sodaß hier die Ausführungszeiten
ebenfalls fast gleich sind.
> Dass die Ausgabe eines floats durch zusätzliche Bibliotheken den> Speicher dann noch zusätzlich aufbläht, ist ja klar.
Beim AVR-GCC mit libc.a werden rund 1K benötigt. Sobald der µC >= 4K
Flash hat, geht float schon mühelos. Aktuell tippe ich ein Programm für
ATtiny44 zur PT1000-Auswertung und Anzeige auf einem 4-stell. LCD.
Codegröße inkl. float-Routinen: 2282 und 26 Byte RAM.
Kein Grund auf float zu verzichten.
Noch etwas: wenn man Integer 10/3 rechnet und dann mit 3 multipliziert
erhält man als Ergebnis 9. Das wundert Niemanden. Erst wenn solche
Sachen bei float passieren ruft die 'Fachwelt': Verrat!
m.n. schrieb:> Zu AVRs: als diese noch keine MUL-Befehle hatten, waren die> Multiplikation für int32 und float fast gleich.
Teurer sind add/sub aufgrund der abhängig von der Exponentendifferenz
notwendigen Mantissenverschiebung. Die entfällt bei Festkomma und ist
bei AVRs recht aufwendig.