Hallo, ich möchte eine 32 Bit Zahl, die nach IEEE754 codiert ist, nach dezimal umrechnen. Ich habe dazu auch schon etliche Anleitungen gefunden wie dies theoretisch zu tun ist. Ich möchte die in "C" tun. Klar ist mit der Aufbau: Sign Exponent Mantisse 0 00000000 00000000000000000000000 Das Vorzeichen bestimmt ob die Zahl Pos. oder Neg. ist. Also nach der Konvertierung mit 1 oder -1 multiplizieren. - verstanden! Der Exponent wird mit "0x7F800000" maskiert und dann mit ( >> 23 ) nach "unten" geshiftet. Zuletzt werden noch 127 abgezogen. - auch soweit klar! Die Mantisse wird mit "0x007FFFFF" maskiert. Sie soll den Teil nach dem "," darstellen. -auch noch klar Es soll jetzt die weggelassene "1" vor dem Komma wieder hinzugefügt werden. Also z.B. "1,010010110101". Hier habe ich mein größtes Problem: Wie soll ich das im C Code abbilden? Ich kann doch keine binäre Kommazahl erstellen???? Dann soll meine Zahl = Vorzeichen*Mantisse*2^Exponent sein. - auch logisch Also würde ich dann 2*2*2*2*2 ... Exponenten mal schreiben. - auch klar Dann muss die Zahl, die immer noch binär ist dezimal gewandelt werden. Was sich mir auch nicht wirklich erschließt. Scheint aber nach dem Muster "8,4,2,1, 0.??" zu gehen? Ich habe schon mehr als 5 Anleitugen im Netz durch, habe aber den Vorgang immer noch nicht verstanden. Vor allem die Umsetzung in "C". Kann mir ein geduldiger Mensch diese Umwandlung näherbringen oder anhand von einem Codebeispiel erklären? Würde mich sehr freuenc :-) Danke und Gruß Ralf
Vielleicht verstehe ich dein Problem grad nicht, aber wenn du nur von float nach dezimal haben willst, dann weise doch dem int einfach den float zu.
@ Ralf (Gast)
>ies theoretisch zu tun ist. Ich möchte die in "C" tun.
Was willst du da rechnen? Das macht der Compiler für dich.
1 | float af; |
2 | int ai; |
3 | |
4 | af = ai; |
5 | ai = af; |
6 | |
7 | print_f ("Integer %i, Float, %f \r\n", ai, af); |
Oder meinst du mit "dezimal" die BCD-Darstellung, wo jede Dezimalziffer der Zahl als Gruppe von 4 Bits dargestellt wird (wie bei den meisten Taschenrechnern üblich)?
Leute, es manchmal auch jemanden, der's einfach nur kapieren will.... Ralf, schau mal hier: Das ist der Standard http://754r.ucbtest.org/standards/754.pdf und hier ist's imho schön erklärt (step by step) http://de.wikipedia.org/wiki/IEEE_754
Ralf schrieb: > Scheint aber nach dem Muster "8,4,2,1, 0.??" zu gehen? Die Wertigkeiten sind so: ... 2^2 2^1 2^0 , 2^-1 2^-2 ... Der ausgerechnete Exponent gibt ja im Grunde nur die Verschiebung des Kommas in der binär dargestellten Zahl an. Dein Beispiel 1,010010110101 Nehmen wir an der exponent ist 128. Also 128 - 127 = 1. Daraus folgt als Endergebnis: 10,10010110101 Also Dezimal: 2,5883789063
Hallo, danke für Eure Antworten. @Frank und Falk Ja, eigentlich würde das mein Compiler machen, aber: Ich empfange über die serielle Schnittstelle eine nach IEEE754 codierte 4 Bit float zahl. Mein Compiler setzt die floats aber anders zusammen: "The CrossWorks C library uses IEEE floating point format as specified by the ISO 60559 standard with restrictions" Wenn ich den empfangenen Wert einfach einem float zuweise kommt nur Müll raus. Habe auch wegen MSB first und LSB first die Bytes testweise getauscht. @Yalu Nein meine ich nicht :-) Vieleicht habe ich mich auch nicht klar ausgedrückt. @K2R Danke für die Links. Bei Wiki ist es wirklich gut erklärt. Die Frage ist nur nach der schlanken Umsetzung in C. @floatexperte Kann der Exponent eigentlich auch negativ werden? Also <= 127 ? Hat jemand mal so eine Umrechnung gemacht und hat in Beispiel? Ich befürchte die Umrechnung wird echt aufwändig. Oder hat jemand eine andere tolle Idee??? :-) Gruß Ralf
@ Ralf (Gast) >Ich empfange über die serielle Schnittstelle eine nach IEEE754 codierte >4 Bit float zahl. Mein Compiler setzt die floats aber anders zusammen: Möglich, aber unwahrscheinlich. >"The CrossWorks C library uses IEEE floating point format as specified >by the ISO 60559 standard with restrictions" Kenn den Standrad nicht, ich tippa ber auch das gleiche Format wie der Rest der C Compiler dieser Welt. >Wenn ich den empfangenen Wert einfach einem float zuweise kommt nur Müll >raus. Habe auch wegen MSB first und LSB first die Bytes testweise >getauscht. Zu 99% liegt der Fehler bei dir. Poste Code.
Hallo Falk, der fragliche Codeausschnitt sieht so aus: Im RxBuffer[] stehen der Reihe nach die Empfangenen Bytes. In [0] das Erste und in [3] das Letzte.
1 | float fTmpZahl = 0; |
2 | uint32_t uiTmpZahl = 0; |
3 | |
4 | uiTmpZahl = (uint32_t)RxBuffer[0] + ((uint32_t)RxBuffer[1] << 8) + ((uint32_t)RxBuffer[2] << 16) + ((uint32_t)RxBuffer[3] << 24); |
5 | |
6 | fTmpZahl = uiTmpZahl; |
In "uiTmpZahl" werden die Bytes richtig eingetragen. Ich habe auch schon die Bytereihenfolge getauscht. Gruß Ralf
>fTmpZahl = uiTmpZahl;
Das geht so nicht;) Mit ner Union könnte man das lösen.
Ralf schrieb: > float fTmpZahl = 0; > uint32_t uiTmpZahl = 0; > > uiTmpZahl = (uint32_t)RxBuffer[0] + ((uint32_t)RxBuffer[1] << 8) + > ((uint32_t)RxBuffer[2] << 16) + ((uint32_t)RxBuffer[3] << 24); > > fTmpZahl = uiTmpZahl; so macht man das auch nicht. Wenn in RXbuffer ein Float steht muss man es auch als float behandeln. float fTmpZahl = 0; memcpy( &fTmpZahl, RxBuffer, 4 ); uint32_t uiTmpZahl = fTmpZahl;
holger schrieb: >>fTmpZahl = uiTmpZahl; > > Das geht so nicht;) Mit ner Union könnte man das lösen. Hallo Holger, Kannst Du mal ein Beispiel angeben? Ich hab unions noch nie gebraucht/benutzt :-) Gruß Ralf
@ Ralf (Gast) >Im RxBuffer[] stehen der Reihe nach die Empfangenen Bytes. In [0] das >Erste und in [3] das Letzte. ;-) wusste ich es doch. Soooo geht es natürlich NICHT! Eher so
1 | float fTmpZahl = 0; |
2 | float *ptmp; |
3 | |
4 | ptmp =(float*)RxBuffer; |
5 | fTmpZahl = *ptmp; |
6 | |
7 | // das könnte auch klappen
|
8 | fTmpZahl = *((float*)RxBuffer); |
GGf. stimmt die Reihenfolge der Bytes nicht, dann musst du die vorher tauschen. Prüfen kannst du deine Rechung, indem du die vier Bytes einzeln ausgeben lässt und durch einen Onlinerechner schickst http://gregstoll.dyndns.org/~gregstoll/floattohex/
Hallo Ralf, zeig doch mal die 4 Bytes und sag dazu welche Zahl du erwartest.
Peter II schrieb: > so macht man das auch nicht. Wenn in RXbuffer ein Float steht muss man > es auch als float behandeln. > > float fTmpZahl = 0; > memcpy( &fTmpZahl, RxBuffer, 4 ); > > uint32_t uiTmpZahl = fTmpZahl; Hallo Peter II, was macht den memcpy in dem Fall anders als das shiften? Ich gebe zu, das das memcpy eleganter ist :-) Ich shifte aber nun mal so gerne :-) Ralf
Ralf schrieb: > was macht den memcpy in dem Fall anders als das shiften? Ich gebe zu, > das das memcpy eleganter ist :-) Ich shifte aber nun mal so gerne :-) es kopiert speicher. floats kann man nicht shiften.
Helmut S. schrieb: > Hallo Ralf, > zeig doch mal die 4 Bytes und sag dazu welche Zahl du erwartest. Hallo Helmut, die übertragene Zahl wird leider nicht angezeigt. Sie müsste aber keiner 0 sein. Ralf
@ Ralf (Gast) >was macht den memcpy in dem Fall anders als das shiften? Was der Name sagt. Kopieren. > Ich gebe zu, >das das memcpy eleganter ist :-) Ich shifte aber nun mal so gerne :-) Du hast das Zahlenformat float noch nicht verstanden und auch nicht seine Repräsentation im Speicher. Mach mal deine Rechnung in Einzelschritten im Simulator bzw. auf Papier. Dann siehst du, was für ein Unsinn du macht. Die Zahl kannst du ja als Float vorgeben.
Peter II schrieb: > Ralf schrieb: >> was macht den memcpy in dem Fall anders als das shiften? Ich gebe zu, >> das das memcpy eleganter ist :-) Ich shifte aber nun mal so gerne :-) > > es kopiert speicher. floats kann man nicht shiften. Ich shifte doch gar kein float. Der Buffer besteht aus 4 Bytes die hintereinander eintrudeln. Mit dem shiften schiebe ich die Bytes einfach an die Positionen in der uint32 Variablen. Ich werd es auf jeden Fall testen. Der Unterschied im Speicher ist mir aber nicht klar. Ich kann es mir morgen mal im Debugger ansehen. Ralf
Ralf, sag doch endlich mal die 4 Bytes oder sind die geheim?
Falk Brunner schrieb: > Du hast das Zahlenformat float noch nicht verstanden und auch nicht > seine Repräsentation im Speicher. Jepp :-) Deshalb poste ich hier ja auch. Auf jeden Fall habe ich jetzt ne Menge Anregungen und wer es morgen ausprobieren. Danke soweit an Euch alle. Ralf
Ralf schrieb: > Mit dem shiften schiebe ich die Bytes einfach > an die Positionen in der uint32 Variablen. richtig, damit hast du ein float in einen int. Im schlimmsten fall in der falschen Reihenfolge weil sich big und Little endian unterscheiden. Wenn die Reihenfolge richtig ist, müsste man nur jetzt casten.
1 | float fTmpZahl = 0; |
2 | uint32_t uiTmpZahl = 0; |
3 | |
4 | uiTmpZahl = (uint32_t)RxBuffer[0] + ((uint32_t)RxBuffer[1] << 8) + ((uint32_t)RxBuffer[2] << 16) + ((uint32_t)RxBuffer[3] << 24); |
5 | |
6 | fTmpZahl = *((float*)&uiTmpZahl); |
aber das umständlicher, an fehleranfälliger.
Helmut S. schrieb: > Ralf, > sag doch endlich mal die 4 Bytes oder sind die geheim? Nein sind sie nicht, Sie ändern sich nur standig mit jeder Übertragung und ich hab die Apperatur jetzt auch nicht griffbereit :-) Ralf
Peter II schrieb: > fTmpZahl = *((float*)&uiTmpZahl); Den cast habe ich unterschlagen. Vieleicht gehts dann ja schon. Ralf
Ralf schrieb: > Den cast habe ich unterschlagen. Vieleicht gehts dann ja schon. es wird nicht immer gehen wegen der Byte Reihenfolge. Dein shift liefert auf ARM was anderes als auf x86. Dann klappt aber auch der cast nicht. nimm memcpy dann ist es offensichtlich was gemacht wird.
Ralf schrieb: > Kann der Exponent eigentlich auch negativ werden? Also <= 127 ? Ja natürlich. > Hat jemand mal so eine Umrechnung gemacht und hat in Beispiel? Ich > befürchte die Umrechnung wird echt aufwändig. Warum? Die Rechnung geht ganz exakt genau so wie oben beschrieben. Es wird halt nur das Komma (in der Binärdarstellung) in die andere Richtung (nach links) verschoben.
@ Ralf (Gast) >hintereinander eintrudeln. Mit dem shiften schiebe ich die Bytes einfach >an die Positionen in der uint32 Variablen. Ja. Aber dann kann man KEINE direkte Zuweisung an eine Float-Variable machen, denn dann INTERPRETIERT der Compiler deine uint32 Zahl als eben uint32. In diesem Fall liegt der Trick eben darin, den Compiler zu überlisten und NUR Daten zu kopieren OHNE sie zu INTERPRETIEREN. Erst wenn das vorbei ist, darf er wieder interpretieren. Klingt verwirrend, geb ich zu ;-) >Ich werd es auf jeden Fall testen. Der Unterschied im Speicher ist mir >aber nicht klar. Dein rxbuffer hat im Speicher die gleiche Reihenfolge wie dein uint32 nach dem Zusammensetzen über die Shiftoperation. Das Problem ist hierbei, dass bei einer Zuweisung variable float = variable int oder anders herum der Compiler immer INTERPRETIERT und eine passende Umwandlungsfunktion aufruft. Es werden NICHT einfach nur 4 Bytes kopiert! Aber genau DAS ist nötig, wenn man einen Float aus vier einzelnen Bytes zusammensetzen will! Kopieren OHNE umzuwandeln. Denn es IST ja schon ein Float. Man muss die 4 Bytes nur am Compiler vorbei in die Variable "mogeln". Ich hoffe das ist ein wenig verständlich.
Hallo Falk, danke für Deine Erklärung. Ich habe es jetzt mit memcpy gemacht und es funst auf anhieb: :-)
1 | memcpy(&f32Zahl,&RxBuffer[0],4); |
Die Bytes im Buffer sind: RxBuffer[0]=0B,RxBuffer[1]=13,RxBuffer[2]=28,RxBuffer[3]=40. In der 32Bit float Zahl: 0x4028130B Die getauschte Reihenfolge hatte ich ja bereits getestet. Es liegt wirklich am "zu schlauen" compiler :-) Danke noch mal an alle bei der Erklärung und Lösungsfindung. Wieder was gelernt :-) Gruß Ralf
@ Ralf (Gast)
>Ich habe es jetzt mit memcpy gemacht und es funst auf anhieb: :-)
OK, probier aber auch mal den cast.
fTmpZahl = *((float*)RxBuffer);
Ralf schrieb: > Danke noch mal an alle bei der Erklärung und Lösungsfindung. Wieder was > gelernt :-) Und? Hast du das Gefühl, das da irgendetwas seltsames passiert oder ist dir 100% klar was in deiner Version passiert ist, was in der jetzigen Version passiert und vor allen Dingen warum das jetzt das korrekte Ergebnis liefert? Denn im Kern geht es um die Fragestellung
1 | int i = 5; |
2 | double d; |
3 | |
4 | d = i; |
was passiert eigentlich bei der Zuweisung. Wie geht der Compiler damit um, dass links vom = ein double steht, während rechts vom = ein int steht? Was muss da passieren? Und warum ist das, was normalerweise absolut erwünscht ist, in deinem Fall völlig kontraproduktiv?
:
Bearbeitet durch User
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.