hallo, ich möchte gerne messdaten auf einem 2x16 zeilen display anzeigen.da ich die daten seriell zum display übertrage muss ich jede einzelne ziffer einer zahl einzeln übertragen.nun mein problem: ich muss die messdaten in einzelne ziffern zerlegen. meine idee: uint8_t Tausender=0; uint8_t Hunderter=0; uint8_t Zehner=0; uint8_t Einer=0; uint8_t Zehntel=0; uint8_t Hundertstel=0; float Zahl=1013.25; uint8_t i; for(i=0;i<4;i++){ while(Zahl!=0){ if(Zahl>=1000){Zahl-=1000;Tausender++;} else if(Zahl>=100){Zahl-=100;Hunderter++;} else if(Zahl>=10){Zahl-=10;Zehner++;} else if(Zahl>=1){Zahl-=1;Einer++;} else if(Zahl>=0.1){Zahl-=0.1;Zehntel++;} else if(Zahl>=0.01){Zahl-=0.01;Hundertstel++;} }} das problem ist jetzt das ich nur 1013,00 übertragen kann da Zehntel und Hundertstel gleich null bleiben und die while unterbrochen wird wenn Zahl anscheinen 0.25 ist . wäre über hilfe dankbar :)
Ich weiß jetzt nicht, wo Dein Gleitkommawert herkommt, aber mit Festkommaarithmetik lassen sich Gleitkommazahlen oft ganz vermeiden und so Rechenzeit und Speicher sparen... Abgesehen davon gibt es zur Umwandlung von Zahlenwerten in ASCII-Strings fertige Funktionen in der stdlib.h. Wenns unbedingt ein Gleitkommawert sein soll, dann schau Dir die Funktion dtostrf mal an.
Bin mir da jetzt nicht ganz sicher, ob hier
>while(Zahl!=0)
nur ein int-Wert geprüft wird.
Evtl. hilft: while(Zahl!=0.0)
schulzki wrote: > Bin mir da jetzt nicht ganz sicher, ob hier >>while(Zahl!=0) > nur ein int-Wert geprüft wird. > Evtl. hilft: while(Zahl!=0.0) Naja, das "!=0" oder wie auch immer kann man in C sowieso getrost weglassen.
1 | while(Zahl) |
2 | {}
|
tut's auch.
Aufpassen bei Floatwerten Man darf Floatwerte aufgrund der internen Zahlendarstellung nicht auf 0 testen sondern auf nur auf einen kleinen wert. Sonst kann es passieren wenn man z.B. fortlaufend von einer Zahl einen kleinen Betrag abzieht das Ergebnis nie 0 wird . Aufgrund der internen Flieskomma darstellung im IEEE Format kann bei einer Berechnung keine 0 entstehen. Die 0 ist im IEEE Format eine Sonderzahl. Besser ist eine Abfrage wie #define FMIN 0.0001 /* kleinster wert der als 0 akzeptiert wird */ /* 0.0001 nur als beispiel hier */ if( fabs(zahl) < FMIN) { tu was } Gruss Helmi
Das Problem ist der float an sich. Warum? Ein float wird mit 4 Byte implementiert. Das bedeutet, dass du in etwa mit 6 signifikanten Stellen rechnen kannst. Bei einer Zahl 1013.25 hast du bereits 4 Stellen für den Vorkommaanteil verbraucht, die beiden restlichen Stellen gehen für die beiden nachkommastellen drauf. Nur: Dann darfst du nicht mit der Zahl rechnen. In dem Momement, in dem du etwas Arithmetik betreibst schrumpfen die 6 Stellen ganz schnell zu 5 Stellen und bei weiteren Berechnungen noch sehr viel schneller zu 4 Stellen. Von den ursprünglichen 6 signifikanten Stellen sind nur noch 4 übrig geblieben, alles andere danch ist nur noch gelogen (*) Nun hast du aber eine Menge Berechnungen. Selbst wenn du ursprünglich mit der Zahl 1013.1 gestartet wärest, würde da nach dem Abziehen der ganzzahligen Anteile keine 0.1 heraus- kommen. Durch die ganzen Zwischenberechnungen hast du sukzessive immer mehr Genauigkeit verloren. Ein etwas vertrauteres Beispiel: Du kennst doch periodische Zahlen. Ein Beispiel: 1/3 Angenommen ich lasse dir 6 signifikante Ziffern zu. Wenn du dann 1/3 berechnen sollst, dann kommt da 0.333333 heraus. Aber so sehr du dich auch windest, 0.333333 * 3 wird nicht mehr 1.0 ergeben. Des Ergebnis 0.999999 ist zwar sehr nahe an 1.0 aber eben nicht exakt 1.0 Wenn ich da jeztt weiter rechne, zb 3 addieren 0.999999 + 3.0 -> 2.99999 (warum nur 5 Nachkommastellen? Zähle die signifikanten Stellen, es sind immer noch 6, aber für die eine jetzt signifikante Vorkommastelle fällt eine Nachkommastelle weg). und das wiederrum durch 3 dividieren 2.99999 / 3 dann kommt als Ergebnis 0.999996 heraus. Rein Mathematisch müsste das Ergebnis immer noch 1.0 sein, aber Floating Point Berechnungen haben nun mal mit Mathematik sehr wenig zu tun. Man sieht aber auch, wie sich der Fehler, je nach tatsächlichen Zahlen und Operationen vergrößert. Soweit zum Dezimalsystem. Im Binärsystem, in dem deine Floating Point Operationen ablaufen ist das im Prinzip nicht anders. Eher sogar schlimmer, weil es dort sehr viel mehr periodische Zahlen gibt. Z.b. ist 0.1, also 1/10, in diesem Zahlensystem nicht exakt darstellbar, da es eine periodische Zahl ist. Konklusio: Vermeide float wenn immer du kannst. Wenns gar nicht anders geht, dann nimm sie, aber achte sehr genau darauf welche Operationen du in welcher Reichenfolge machst und welche Zahlen da beteilgt sind. Leider gibt es da kein Patentrezept, sondern jeder einzelne Fall muss seperat für sich untersucht werden. Und solche Untersuchungen können einen in den Wahnsinn treiben. Rechnen mit Gleitkommazahlen ist wie das Umschaufeln eines Sandhaufens. Je öfter man es macht, desto mehr Sand verliert man und desto mehr Dreck mischt man in den Sand. (*) gelogen ist ein hartes Wort. Natürlich kann man erklären wie die weiteren Nachkommastellen zustande kommen, aber da muss man schon sehr tief in Fliesskommaverarbeitung einsteigen.
Um Dir jetzt ein Lösung an die Hand zu geben, wie wäre es mit folgendem?
1 | float zahl = 1023.25; |
2 | char puffer[8]; // 7 Ziffern + abschließende Null |
3 | if ( sprintf( puffer, "%04.2f", zahl) == 7 ) |
4 | {
|
5 | printf("Die Ausgabe der Zahl in den Puffer war erfolgreich!\n"); |
6 | }
|
7 | printf("Die Zeichenkette der Zahl %f ist %s\n", zahl, puffer ); |
Dann kannst Du Zeichen für Zeichen aus der Zeichenkette holen, bis Du auf die abschließende Null triffst. Dann erlöst Dich zwar nicht von etwaigen Problemen mit der Gleitkommaarithmetik, aber immerhin eine Lösung!
Spar dir den Ärger mit float und rechne einfach mit ganzen Zahlen: float Zahl=1013.25; long lzahl = Zahl*100; tausender = lzahl/100000L; lzahl = lzahl%100000L; hunderter = lzahl/10000; usw....
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.