![]() |
Mal wieder HexToFloat
Hallo,
ich habe folgendes Problem: Ich bekomme über eine Schnittstelle einen String, der eine Hexadezimalzahl repräsentiert (4 Zeichen lang), also z.B. 'FF E4' oder '00 03'. Dieser String muss jetzt in einen Gleitkommawert umgewandelt werden. Ich habe eine Funktion dafür, die den Wert in binärstring umwandelt so dass dann die Mantisse und der Exponent ausgerechnet werden kann. Die Funktion gibt dann das Ergebnis der Rechnung result := mantisse * power(2,exponent) aus. Das Problem ist jetzt, dass ich mit der Funktion eine normalisierte Zahl (also z.B. 9.17963e-41) als Ergebnis bekomme, ich hätte aber gerne eine 'normale' Kommazahl (also z.B. 0,00000917). Hat jemand eine Idee wie man das hinkriegt, oder gibt es vielleicht sogar noch eine einfachere Methode einen Hex-String in eine Kommazahl zu konvertieren? (Tante Google hat mir leider auch nicht geholfen) |
AW: Mal wieder HexToFloat
Was soll das für ein Format sein? 4 Hex-Zeichen sind 16-Bit, das ist ein Format, das ungeöhnlich ist (single hat 32-Bit). Ohne Dokumentation des internen Aufbaus des 16-Bit-Wortes kann man wohl wenig sagen oder helfen.
|
AW: Mal wieder HexToFloat
Nein, du bekommst eine unformatierten "binären" Wert.
Wie du diesen Wert dann darstellst, also wieder in einen String umwandelst, ist dir überlassen. z.B. ![]() ![]() |
AW: Mal wieder HexToFloat
Du kannst folgendes machen:
Delphi-Quellcode:
Prinzipiell kannst du mit FloatToStrF oder Format die Zahl (wenn du sie als String ausgeben willst) auf X Nachkommastellen formatieren.
function HexToSingle(hex: String): Single;
var tmp: Cardinal; begin tmp := StrToInt('$' + hex); Move(tmp, Result, SizeOf(Cardinal)); end; var f: Single; begin f := HexToSingle('FFE4'); Caption := FloatToStr(f); end; Hinweis: 9.17963e-41 ist NICHT 0,00000917. Die Darstellung "9.17963e-41" wird benutzt, weil die Zahl ausgeschrieben so aussehen würde: 0,0000000000000000000000000000000000000000917963 |
AW: Mal wieder HexToFloat
Zitat:
Delphi-Quellcode:
function HexToSingle(hex: String): Single;
var tmp: smallint; begin tmp := StrToInt('$' + hex); Result := tmp; end; |
AW: Mal wieder HexToFloat
Zitat:
|
AW: Mal wieder HexToFloat
Zitat:
|
AW: Mal wieder HexToFloat
Vielleicht waren es auch nur schlechte (zu kurze) Beispiele?
Ich habe es so interpretiert dass er/sie "echte" Floats als Hex-String erhält. Seine/Ihre Vorgehensweise diese umzuwandeln und dass mein Code das gleiche Ergebnis erzielt scheint das zu bestätigen. Dass die Ergebnisse nicht so aussehen als wären sie gewollt stimmt wohl. Es ist wahrscheinlich nicht auszuschließen dass er/sie selbst nicht genau weiß diese Hex-Strings darstellen und wie sie decodiert werden müssen. Von daher: Wir brauchen mehr Infos. |
AW: Mal wieder HexToFloat
Hmm
Also ich vermute, dass es sich um HalfFloat oder auch Float16 handelt. Diese haben nur 2 Bytes und werden in Hex eben so dargestellt. Jedoch müssen diese in Delphi umgerechnet werden auf z.B. single. Hierbei wird daraus (glaube ich) zunächst ein WORD (mit StrToInt('$'+AString)) gemacht und dieses dann nach Single konvertiert. Beispiele habe ich keine... |
AW: Mal wieder HexToFloat
Zitat:
Das Problem ist, dass ein 16-Bit Float in einem 32-Float nicht den gleichen Wert hat. |
AW: Mal wieder HexToFloat
Hmm..
Müsste sich mit dieser beschreibung nicht das WORD Bitweise zerlegen lassen und damit dann die Float richtig erstellt werden, unabhänging ob nun Single oder Double... ![]() |
AW: Mal wieder HexToFloat
Zitat:
|
AW: Mal wieder HexToFloat
Das Umwandeln von HEX zu Float hat er doch schon?
Nur das weitere Umwandeln von Float zu "String mit Kommastellen" hing. |
AW: Mal wieder HexToFloat
Ich begreife immer noch nicht wo denn hier überhaupt Nachkommastellen herkommen sollen?
Wird 0000 übertragen ist das 0, wird FFFF übertragen ist das 65535 Ciao Stefan |
AW: Mal wieder HexToFloat
Zitat:
es kommt ja darauf an wie die Bits interpretiert werden (müssen) Gruß K-H |
AW: Mal wieder HexToFloat
Ich bleibe dabei, wir brauchen mehr Infos. Für $FFE4 würde - wie leicht aus der Wiki-Darstellung folgt - das Ergebnis ein NaN sein, da der Exponent binär 11111 ist.
|
AW: Mal wieder HexToFloat
Es sind 16 Bit als HEX gegeben.
Diese werden in Mantisse und Exponent zerlegt und in einen Float umgerechnet. z.B. siehe WikiLink , aber welche Teile jetzt wieviele Bits haben, ist uns egal, den den Teil hat der TE bereits. Das Problem was er hat, dass mit seine Float-To-Str-Funktion, welche er uns nicht verraten hat, eben im "falschen" Format raus kommt, wenn er den "Float" in einen menschenlesbaren String umwandeln will. Und das läßt sich mit den richtigen passenden Umwandlungsfunktionen beheben, welche bereits genannt wurden. |
AW: Mal wieder HexToFloat
Falls es sich doch um ein 16-Bit Float handeln sollte habe ich mal was gebaut.
Ist sicherlich nicht das schönste auf der Welt, aber funktioniert soweit ich das getestet habe: EDIT: Diese Version ist fehlerhaft! Ein paar Posts weiter unten ist die korrigierte Version!
Delphi-Quellcode:
function HexToFloat16(hex: String): Single;
function FractionToFloat(frac: Cardinal): Single; var i: Integer; begin Result := 0; for i:=0 to 10 do begin if (frac shr (10-i)) <> 0 then Result := Result + Power(2, -(11-i)); end; end; var tmp: Word; resultBin: Cardinal; sign: Cardinal; exp: Cardinal; frac: Cardinal; begin tmp := StrToInt('$' + hex); frac := (tmp and $3FF); exp := ((tmp shr 10) and $1F);; sign := (tmp shr 15); if (exp = $1F) then begin if (frac = 0) then begin if (Sign = 0) then Result := Infinity else Result := NegInfinity; end else Result := NaN; end else if (exp = 0) then begin if (frac = 0) then begin if (Sign = 0) then Result := 0 else Result := -0; end else begin // Subnormals if (sign = 0) then Result := Power(2,-14) * FractionToFloat((frac shl 1) + 1) else Result := -Power(2,-14) * FractionToFloat((frac shl 1) + 1); end; end else begin resultBin := (frac shl 13) or ((exp - 15 + 127) shl 23) or (sign shl 31); Move(resultBin, Result, SizeOf(Cardinal)); end; end; |
AW: Mal wieder HexToFloat
Hmm..
@Neutral General Irgendwie scheint die berechnung nicht zu passen.. Wenn der exp = 0 ist, dann kommen falsche Werte heraus. Bei $0001 = 0 00000 0000000001 Kommt lt. Wiki 5,96046447753906E-8 heraus, es ist der minimum positive Subnormale. Bei Dir leider 4,57763671875E-5 Wenn man einen Exponenten hat, dann passt deine Berechnung. (Habe leider keine Möglichkeit (Fähigkeit) es selbst zu lösen ;) ) ![]() |
AW: Mal wieder HexToFloat
Korrigierte Version:
Delphi-Quellcode:
function HexToFloat16(hex: String): Single;
function FractionToFloat(frac: Cardinal): Single; var i: Integer; begin Result := 0; for i:=0 to 10 do begin if ((frac shr i) and 1) <> 0 then Result := Result + Power(2, -(11-i)); end; end; var tmp: Word; resultBin: Cardinal; sign: Cardinal; exp: Cardinal; frac: Cardinal; begin tmp := StrToInt('$' + hex); frac := (tmp and $3FF); exp := ((tmp shr 10) and $1F);; sign := (tmp shr 15); if (exp = $1F) then begin if (frac = 0) then begin if (Sign = 0) then Result := Infinity else Result := NegInfinity; end else Result := NaN; end else if (exp = 0) then begin if (frac = 0) then begin if (Sign = 0) then Result := 0 else Result := -0; end else begin // Subnormals if (sign = 0) then Result := Power(2,-14) * FractionToFloat((frac shl 1)) else Result := -Power(2,-14) * FractionToFloat((frac shl 1)); end; end else begin resultBin := (frac shl 13) or ((exp - 15 + 127) shl 23) or (sign shl 31); Move(resultBin, Result, SizeOf(Cardinal)); end; end; |
AW: Mal wieder HexToFloat
Passt :thumb:
Jetzt nur noch die umgekehrte Version (von Single nach HEXStr) ... 8-) :wink: |
AW: Mal wieder HexToFloat
Zitat:
|
AW: Mal wieder HexToFloat
Zitat:
|
AW: Mal wieder HexToFloat
Vielen Dank für die vielen Tipps. Dann werde ich wohl mal eingiges ausprobieren wenn ich wieder dazu komme.
|
AW: Mal wieder HexToFloat
Hallo zusammen,
ich war gerade auch auf der Suche nach dieser Routine und hab vor diesen Forum folgendes gefunden: ![]() Dort ist auch Code in anderer Sprache zu finden. Ich hab die Hexwerte von Netzwerkprotokoll (BACnet) dort getestet und funktioniert: 0100 .... = Application Tag Number: Real (ANSI/IEE-754 floating point) (4) present-value: 417.500000 (Real) Hexwert: 43D0C000 Vielleicht bringt es was. |
AW: Mal wieder HexToFloat
Ich habe nach dem Standard mal gesucht und folgendes gefunden:
![]() Bei mir hat es dann funktioniert:
Delphi-Quellcode:
var
Data: array[0..3] of byte; X: Real; begin Data[3] := aMsg.TheMessage[offset]; Data[2] := aMsg.TheMessage[offset + 1]; Data[1] := aMsg.TheMessage[offset + 2]; Data[0] := aMsg.TheMessage[offset + 3]; X := PSingle(@data)^; |
AW: Mal wieder HexToFloat
Edit: War Unsinn
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 05:22 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz