Forum: Mikrocontroller und Digitale Elektronik Typecast Arduino


von Andi (Gast)


Lesenswert?

Hallo Leute!

Ich suche gerade nach einer Möglichkeit die Anzahl der Nachkommastellen 
einer float-Zahl mittels eines Arduino Micro zu bestimmen. Grundsätzlich 
habe ich mir das so gedacht:

*Typecast der float-Zahl zu int
*Falls Differenz zwischen float-Zahl und int Zahl ungleich null, wird 
die float-Zahl mit 10 multipliziert
*Zähler inkrementieren
*Schleife beginnt von vorne

Hier mal mein Code:
1
uint8_t getDecimalPlace(float val) {
2
  uint8_t i = 0;
3
  uint_32_t n = int(val);
4
  while((val-n) != 0) {
5
    i++;
6
    val *= 10;
7
    n = int(val);
8
  }
9
  return i;
10
}

Mit einer Nachkommastelle funktioniert das auch wunderbar. Wenn ich 
jedoch zwei Nachkommastellen habe, gibt es anscheinend Probleme mit dem 
Typecast. Zumindest spuckt mir mein Debugging für Arme (print() per 
serieller Schnittstelle) etwas falsches aus:

Im ersten Schleifendurchlauf ist noch alles klar, val = 47.4, n = 47. Im 
zweiten bekomme ich jedoch schon falsche Werte: val = 474, n= 473. Und 
das pflanzt sich dann so fort und die Schleife wird nie verlassen.

Kann mir da jemand ein paar Tipps geben woran das liegen könnte oder ob 
man das grundsätzlich anders machen sollte?


Grüße
Andi

von Karl H. (kbuchegg)


Lesenswert?

Andi schrieb:

> Kann mir da jemand ein paar Tipps geben woran das liegen könnte oder ob
> man das grundsätzlich anders machen sollte?

Was du übersiehst ist, dass deine Zahl im Computer nicht dezimal 
gespeichert wird sondern binär. Das bedeutet aber auch, dass sie anders 
im Speicher steht und auch unter Umständen einen etwas anderen Wert hat.

Ohne jetzt die Binärrepräsentierung kontrolliert zu haben, ist es zb 
möglich, dass die Zahl 47.4 in Binärform gar nicht exakt darstellbar 
ist. Binär ist zum Beispiel 47.3999999 möglich. Das ist fast 47.4 aber 
eben nicht ganz. Rundet man die Ausgabe auf 2 Stellen, dann steht in der 
Ausgabe tatsächlich 47.4 (beim printf). Das bedeutet aber nicht, dass 
die Zahl intern tatsächlich dem Wert 47.4 entspricht.


Floating Point rechnen ist in einem COmputer keineswegs eine simple 
Sache und verhält sich nicht immer so, wie man sich das landläufig so 
vorstellt. Zwischen 0.0 und 1.0 gibt es unendlich viele rationale 
Zahlen. Dadurch dass man aber nicht unendlich viele Bits zur Verfügung 
hat, muss man Abstriche machen. Nicht alle Zahlen zwischen 0.0 und 1.0 
sind in einem Computer exakt darstellbar, sondern müssen durch die 
nächstliegende Zahl (im Binärsystem) angenähert werden. Tatsächlich ist 
sogar die große Mehrheit aller rationalen Zahlen nicht exakt 
darstellbar.
Das ist ein bischen so, wie du das ausgerechnte Ergebnis von 1.0/3.0 
(also 0.33333333...) eben nicht niederschreiben kannst, selbst wenn du 
über alles Papier dieser Welt verfügen würdest. Und das Ergebnis davon, 
das du praktisch erhältst ist dann eben nicht mehr 1.0, wenn man es mit 
3.0 multipliziert. Das Ergebnis ist 0.99999999999... eine Zahl die fast 
1.0 ist, aber eben nicht genau 1.0

von Dr. Sommer (Gast)


Lesenswert?

So was macht man am besten gar nicht. zB die Zahl 0.1 ist nicht als 
float darstellbar, sondern nur eine Approximation mit ca. 15 
Dezimalziffern - willst du die wirklich im Ergebnis haben? (printf 
rundet bei der Anzeige sodass es so aussieht als könne ein float 0.1 
sein).

Wenn's doch sein muss zerleg die Zahl in mantisse & exponent, zähle die 
nullen im ersteren und rechne damit ein bisschen rum.

PS: Genau nachlesen wie floating point funktioniert und überlegen ob 
fixed  point nicht doch besser ist. Arduino mit AVR ist eh extrem lahm 
bei float.

von Karl H. (kbuchegg)


Lesenswert?

Andi schrieb:

> Kann mir da jemand ein paar Tipps geben woran das liegen könnte oder ob
> man das grundsätzlich anders machen sollte?

Die Frage ist: was willst du eigentlich aus einer höheren Sicht aus 
machen?

Der Normalfall ist, das man im Vorfeld weiß, wieviele Kommastellen 
benötigt werden und nicht der, dass man die bestimmen muss.

von Hanno (Gast)


Lesenswert?

Wandle die Zahl in einen String um. Dann hast du erst mal den aktuellen 
Zustand eingefroren und kannst von Rechts an die Stellen bis zum Komma 
zählen.

von Dr. Sommer (Gast)


Lesenswert?

Hanno schrieb:
> Wandle die Zahl in einen String um.

Dann hat man aber entweder die Anzahl Ziffern einer gerundeten Zahl, 
oder viel zu viele... Sehr nützlich.

von Kaj (Gast)


Lesenswert?

Karl Heinz schrieb:
> Ohne jetzt die Binärrepräsentierung kontrolliert zu haben, ist es zb
> möglich, dass die Zahl 47.4 in Binärform gar nicht exakt darstellbar
> ist.
Jop.

Dr. Sommer schrieb:
> zB die Zahl 0.1 ist nicht als
> float darstellbar, sondern nur eine Approximation
Jop.

Jede Zahl die hinter dem Komma auf 1,2,4,6 oder 8 endet ist binaer nicht 
exat darstellbar, bzw. nur zahlen die hinter dem Komma auf 0 oder 5 
enden sind binaer exakt darstellbar.

Beweis:
0.1 * 2 = 0.2
0.2 * 2 = 0.4 <--------------+
0.4 * 2 = 0.8                |
0.8 * 2 = 1.6 <-- uebertrag  |
0.6 * 2 = 1.2 <-- uebertrag  |
0.2 * 2 = 0.4 ---------------+

und so gehts weiter bis zum ende aller tage.

von Mike (Gast)


Lesenswert?

Andi schrieb:
> Ich suche gerade nach einer Möglichkeit die Anzahl der Nachkommastellen
> einer float-Zahl mittels eines Arduino Micro zu bestimmen.

Nimm dir als Startwert Delte z.B. die Zahl 0.5
Dann rechne
 y = 1 - Delta

In einer Schleife halbierst du Delta immer weiter, bis y=1.0 raus kommt.
Wenn du dir dabei y immer ausgeben läßt, siehst du auch wieviel Stellen 
deine Float-Zahlen repräsentieren können.

von Andi (Gast)


Lesenswert?

Karl Heinz schrieb:
> Der Normalfall ist, das man im Vorfeld weiß, wieviele Kommastellen
> benötigt werden und nicht der, dass man die bestimmen muss.

Ich habe hier acht Siebensegmentanzeigen, die ich ansteuern möchte und 
würde gerne eine Funktion haben, in die ich die darzustellende Zahl 
einfach eintippe, bspw.
1
showNumber(2432.97);
Mit ganzen Zahlen habe ich das bisher problemlos realisieren können, bei 
Kommazahlen müsste ich jedoch wissen an welcher Stelle genau das Komma 
steht, um die Anzeige dementsprechend anzusteuern.

Dr. Sommer schrieb:
> Wenn's doch sein muss zerleg die Zahl in mantisse & exponent, zähle die
> nullen im ersteren und rechne damit ein bisschen rum.

Daran habe ich auch bereits gedacht, nur wie komme ich an die Mantisse 
und den Exponenten ran?

Vielen Dank! :)

von Bitflüsterer (Gast)


Lesenswert?

Andi schrieb:
> Karl Heinz schrieb:
>> Der Normalfall ist, das man im Vorfeld weiß, wieviele Kommastellen
>> benötigt werden und nicht der, dass man die bestimmen muss.
>
> Ich habe hier acht Siebensegmentanzeigen, die ich ansteuern möchte und
> würde gerne eine Funktion haben, in die ich die darzustellende Zahl
> einfach eintippe, bspw.
1
showNumber(2432.97);
> Mit ganzen Zahlen habe ich das bisher problemlos realisieren können, bei
> Kommazahlen müsste ich jedoch wissen an welcher Stelle genau das Komma
> steht, um die Anzeige dementsprechend anzusteuern.

Dann nützt Dir die Anzahl der Nachkommastellen sowieso nicht viel. Denn 
wenn Du Dich allein danach richtest, weisst Du ja nicht ob die Zahl noch 
in die Anzeige passt. Sie mag ja zuviele Vorkommastellen haben.

Runden aber geht immer. Und mit der Anzahl der Vorkommastellen, weisst 
Du auch wo das Komma hingehört. Das geht mit dem Logarithmus zur Basis 
10.

Wenn Karl Heinz was anderes schreibt hat im Zweifel er recht. :-)

von Dr. Sommer (Gast)


Lesenswert?

Andi schrieb:
> Daran habe ich auch bereits gedacht, nur wie komme ich an die Mantisse
> und den Exponenten ran?
1
uint32_t raw = *((uint32_t*) (&myFloat));
2
uint32_t mantissa = raw & 0x7FFFFFFF;
3
uint32_t exp = (raw >> 23) & 0xFF;
Es ist aber wie gesagt dringend davon abzuraten die Ziffern zählen zu 
wollen... Denn zB wenn du die Anzahl Ziffern von 2432.97 abfragst, wirst 
du 17 enthalten, denn 2432.97 ist nicht als float darstellbar und wird 
stattdessen durch 2432.969970703125 approximiert, was 17 Stellen hat. 
Wie willst du das jetzt darstellen??

von Andi (Gast)


Lesenswert?

Bitflüsterer schrieb:
> Dann nützt Dir die Anzahl der Nachkommastellen sowieso nicht viel. Denn
> wenn Du Dich allein danach richtest, weisst Du ja nicht ob die Zahl noch
> in die Anzeige passt. Sie mag ja zuviele Vorkommastellen haben.

Ich richte mich nicht nur allein danach; mir ist schon klar, dass die 
Zahl unter Umständen nicht voll anzeigbar ist. Aber das ist sowieso 
nicht so wichtig, da der anzeigbare Zahlenbereich direkt durch die 
Funktion eingeschränkt werden soll (einfachster Fall: Kommentar mit 
"zahl=0...xxxxxxxx als Parameter möglich" vor der Funktion ;)).Das Ganze 
ist eh nur für mich gedacht, d.h. das wird keine öffentliche Library, wo 
im Zweifelsfall alle möglichen (und evtl. sinnlosen) Benutzereingaben 
verarbeitet bzw. abgefangen werden sollen.

von Andi (Gast)


Lesenswert?

Dr. Sommer schrieb:
> Es ist aber wie gesagt dringend davon abzuraten die Ziffern zählen zu
> wollen... Denn zB wenn du die Anzahl Ziffern von 2432.97 abfragst, wirst
> du 17 enthalten, denn 2432.97 ist nicht als float darstellbar und wird
> stattdessen durch 2432.969970703125 approximiert, was 17 Stellen hat.
> Wie willst du das jetzt darstellen??
Das habe ich tatsächlich nicht bedacht, danke für den Einwand! ;)

von Bitflüsterer (Gast)


Lesenswert?

Andi schrieb:
> Bitflüsterer schrieb:
>> Dann nützt Dir die Anzahl der Nachkommastellen sowieso nicht viel. Denn
>> wenn Du Dich allein danach richtest, weisst Du ja nicht ob die Zahl noch
>> in die Anzeige passt. Sie mag ja zuviele Vorkommastellen haben.
>
> Ich richte mich nicht nur allein danach; mir ist schon klar, dass die
> Zahl unter Umständen nicht voll anzeigbar ist. Aber das ist sowieso
> nicht so wichtig, da der anzeigbare Zahlenbereich direkt durch die
> Funktion eingeschränkt werden soll (einfachster Fall: Kommentar mit
> "zahl=0...xxxxxxxx als Parameter möglich" vor der Funktion ;)).Das Ganze
> ist eh nur für mich gedacht, d.h. das wird keine öffentliche Library, wo
> im Zweifelsfall alle möglichen (und evtl. sinnlosen) Benutzereingaben
> verarbeitet bzw. abgefangen werden sollen.

Ob das nun eine "öffentlich" Library werden soll oder nicht spielt dabei 
garkeine Rolle.
Normalerweise hat man eine Forderung, das Zahlen in dem und den Bereich 
mit den und den Nachkommastellen angezeigt werden sollen.
Ob Du Die nun per Kommentar oder sogar funktional einschränkst ist eine 
Sache. Die andere aber ist, wie Du konkret die Zahl anzeigst. Welche 
Methoden usw. Du anwendest.
Nur darauf bezog sich meine Antwort.
Und eben dabei die Anzahl der der Nachkommastellen heranzuziehen ob 
allein oder mit Einschränkung eines Wertebereichs ist ein komplizierter 
Umweg im Vergleich zu der Methode die Anzahl der Vorkommastellen 
festzustellen. Meine ich wenigstens.

Aber gut. Vielleicht verstehe ich Deine Frage nicht und halte mich 
besser 'raus.

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.