Forum: Mikrocontroller und Digitale Elektronik Float Formatierung


von Bruno N. (nusbr)


Lesenswert?

Hallo
Habe ein Frage zum float Datentyp. Benutze ein Grafikdisplay und möchte 
dort mehrere Fliesskommazahlen darstellen. Leider haben die Werte 
unterschiedliche Dezimalstellen und können nicht gleich eingerückt 
werden. Wie mann die Nachkommastellen ändert, weiss ich. Gibt es auch 
eine Möglichkeit, die "Vorkommastellen" anzugeben?

U8glib.print(float(wert),3);


Beispiel wie es ist:
1.635
243.757

Beispiel wie es sein sollte:
001.635
243.757

Danke für die Unterstützung

von Nils S. (kruemeltee) Benutzerseite


Lesenswert?

sprintf(temp_str, "%03f", wert);

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Genauer gesagt:
1
  char temp_str[20];
2
  snprintf(temp_str, sizeof(temp_str), "%06.3f", wert);
3
  U8glib.print(temp_str);

von Karl H. (kbuchegg)


Lesenswert?

Jörg W. schrieb:

>   snprintf(temp_str, sizeof(temp_str), "%06.3f", wert);

Aber Vorsicht.
Bei der Feldbreite, den 6, ist der Dezialpunkt und ein mögliches 
Vorzeichen auch schon mit eingerechnet. Vor allen Dingen auf den 
Dezimalpunkt vergisst man gerne.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl H. schrieb:
> Vor allen Dingen auf den Dezimalpunkt vergisst man gerne.

Stimmt, 7.3 wäre besser.

Das snprintf() hilft dabei dagegen, dass bei einer (auch nur
versehentlich) sehr großen Zahl irgendwo der bereitgestellte
Speicherplatz überläuft.

von Bruno N. (nusbr)


Lesenswert?

Danke, für die vielen Beiträge. Werde dies spätestens morgen 
ausprobieren.

von Tim S. (tim_seidel) Benutzerseite


Lesenswert?

Jörg W. schrieb:
> Das snprintf() hilft dabei dagegen, dass bei einer (auch nur
> versehentlich) sehr großen Zahl irgendwo der bereitgestellte
> Speicherplatz überläuft.

Aber Vorsicht. Nicht alle Implementationen setzen in jedem Fall eine 
Terminierung (vgl Microsoft VC: _snprintf) auch, wenn sie es sollten. So 
kann man sich je nach System einen Folge-Fehler und eben wieder einen 
Puffer-Überlauf einhandeln.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Tim S. schrieb:
> Microsoft VC: _snprintf

Sie werden schon wissen, warum sie da einen Unterstrich davorsetzen …

Aus dem Kontext (U8glib) würde ich mal schlussfolgern, dass das für
einen AVR ist, und das snprintf() der avr-libc verhält sich in dieser
Hinsicht so, wie es vom C99-Standard vorgeschrieben ist.

von Bruno N. (nusbr)


Lesenswert?

Leider wird Float snprintf bei der Arduino IDE nicht unterstützt.

Gibt es noch eine andere Möglichkeit?

von Elec-lisper (Gast)


Lesenswert?

Mach es von Hand. Mit ein wenig Mathematik wie es sprintf machen würde.
Du musst nur geschickt durch 10 teilen und mit cast nach int die 
Nachkommastellen
Entfernen. Bspw. 23,5 / 10 = 2,35 cast int = 2 jetzt jagst du das durch 
switch case
Und gibst ne '2' aus. Jetzt nimmst du die 2 wieder mal 10 und machst: 
23,5 - 20 und
Entfernst damit die höchste stelle. => 3,5 jetzt teilst du durch eine 
zehnerpotenz
Weniger also 10^0 = 1 cast nach int switch case und hast '3'. Dann 3 * 
10^0 abziehen
Und durch die nächste potenz teilen. 0,5 / 10^-1 = 5. Usw usf.

von W.S. (Gast)


Lesenswert?

Bruno N. schrieb:
> Leider wird Float snprintf bei der Arduino IDE nicht unterstützt.
>
> Gibt es noch eine andere Möglichkeit?

Ja.

Guck in die Lernbetty hier im Forum und dort nach "conv.c". Da hast du 
sowohl Integer- als auch Float-Konvertierung in simplem C, sollte also 
problemlos verstehbar sein und auch auf nem AVR gehen.

W.S.

von (prx) A. K. (prx)


Lesenswert?

Grundlage der printf Konvertierung ist oft eine Library-Funktion fcvt 
oder _fcvt, die ggf. auch direkt verwendet werden kann, wenn das der 
einzige Grund wäre, das vollständige printf reinzuziehen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Er könnte auch dtostre() oder dtostrf() benutzen.

Möglicherweise könnte man aber den Arduino-Kram auch davon überzeugen,
die Gleitkommaversion der Bibliothek zu nutzen.

A. K. schrieb:
> Grundlage der printf Konvertierung ist oft eine Library-Funktion fcvt
> oder _fcvt

In der avr-libc ist es die Funktion __ftoa_engine().

von Kay R. (1kay)


Lesenswert?

Elec-lisper schrieb:
> switch case

Was "switch und case" hier sollen, weiß ich nicht, ich habe das mal so 
gemacht:
1
void printFloat(char* buff, float value) {
2
  int intval = (int) floor(value);
3
  int decval = (int) floor((value - (float) intval) * 1000.0);
4
  sprintf(buff, "%d.%03d", intval, decval);
5
}

snprintf() wäre natürlich besser, und statt "%d.%03d" wäre bei dir wohl 
"%03d.%03d" angebracht.

Ich weiß, da sind überflüssiger Code und Casts drin, das überlasse ich 
dem Optimierer, es zu entfernen. Ich will halt meinen eigenen Kram auch 
nach 2 Jahren noch von der Intention her verstehen :-)

von Elec-lisper (Gast)


Lesenswert?

Kay R. schrieb:
> Was "switch und case" hier sollen, weiß ich nicht,

Das war für den Fall, dass keim sprintf oder floor zur Verfügung steht.

Kay R. schrieb:
> Ich will halt meinen eigenen Kram auch nach 2 Jahren noch von der
> Intention her verstehen :-)

Das erledigt ja die korrekte Benennung und die
Kommentare im Code für dich.

von achim (Gast)


Lesenswert?

Du kannst doch einfach anstelle von switch case ASCII 0 + x rechnen und 
bekommst auch die richtige Zahl raus.

Spart code size, ist schneller, da nur eine instruktion und einfach zu 
verstehen.

Wobei die paar Instruktionen, die man spart sind gegen float 
Berechnungen auch egal.

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
Noch kein Account? Hier anmelden.