Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   HexString to IEEE574 64 Bit (https://www.delphipraxis.net/196340-hexstring-ieee574-64-bit.html)

tofse 14. Mai 2018 12:13

HexString to IEEE574 64 Bit
 
Hallo,

ich habe mir das hier zusammengebaut. Meine Frage ist, geht das noch optimaler, mit evtl. Delphi eigenen Funktionen?

Delphi-Quellcode:
function ByteArrayToHexString(BA: TBytes; Sep: string = ''): string;
var
  i, k: integer;
begin
  result:='';

  if Sep='' then begin
     for i:=low(BA) to high(BA) do
       result := result + IntToHex(BA[i], 2);
  end else begin
     k:=high(BA);
     for i:=low(BA) to k do begin
        result:= result + IntToHex(BA[i], 2);
        if k<>i then result := result + Sep;
     end;
  end;
end;

function HexToBin(Hexadecimal: string): string;
const
  BCD: array [0..15] of string =
    ('0000', '0001', '0010', '0011', '0100', '0101', '0110', '0111',
    '1000', '1001', '1010', '1011', '1100', '1101', '1110', '1111');
var
  i: integer;
begin
  for i := Length(Hexadecimal) downto 1 do
    Result := BCD[StrToInt('$' + Hexadecimal[i])] + Result;
end;

function BinToInt(Value: string): Integer;
var
  i, iValueSize: Integer;
begin
  Result := 0;
  iValueSize := Length(Value);
  for i := iValueSize downto 1 do
    if Value[i] = '1' then Result := Result + (1 shl (iValueSize - i));
end;

Function VariantToBytes(Const Value: Variant): TBytes;
Var
  Size: Integer;
  pData: Pointer;
Begin
  Size := Succ(VarArrayHighBound(Value, 1) - VarArrayLowBound(Value, 1));
  SetLength(Result, Size);
  pData := VarArrayLock(Value);
  Try
    Move(pData^, Pointer(Result)^, Size);
  Finally
    VarArrayUnlock(Value);
  End;
End;

function OB2Result(const OrigDicom:OleVariant):Extended;
  var hexstr,binStr,mantisse,exponent:String;
      mantisseExt,exponentExt,Ergebnis:Extended;
      I:Integer;
begin
  hexstr:= ByteArrayToHexString(VariantToBytes(OrigDicom));
  // little Endian
  hexstr:=copy(hexstr,15,2)+copy(hexstr,13,2)+copy(hexstr,11,2)+copy(hexstr,9,2)+copy(hexstr,7,2)+copy(hexstr,5,2)+copy(hexstr,3,2)+copy(hexstr,1,2);
  binStr:=HexToBin(hexstr);
  mantisse:=copy(binstr,13,52);
  mantisseExt:=0.0;
  for I := 1 to length(mantisse) do
  begin
    if copy(mantisse,i,1)='1' then
    begin
      mantisseExt:=power(2,-i)+mantisseExt;
    end;
  end;
  mantisseExt:=mantisseExt + 1.0;
  exponent:=copy(binstr,2,11);
  exponentExt:=BinToInt(exponent)-1023;
  Ergebnis := 0.0;
  if copy(binstr,1,1) = '0' then
    Ergebnis:=power(2,exponentExt) * mantisseExt
  else
    Ergebnis:=-1 * power(2,exponentExt) * mantisseExt;
  Result:=Ergebnis;
end;

Als Beispiel z.B. E17A14AE47613740 entspricht 23.38

Die Übergabe hier
Delphi-Quellcode:
function OB2Result(const OrigDicom:OleVariant):Extended;
bekomme ich als OleVariant, das zur Info.

Das alles funktioniert, bin echt froh, dass ich es hinbekommen habe, jetzt geht es ans Optimieren.
Vielleicht gibt es den einen oder anderen Tipp?

Gruß
Christof

TiGü 14. Mai 2018 12:49

AW: HexString to IEEE574 64 Bit
 
Den ersten Googletreffer "delphi IEEE574" fandest du nicht brauchbar?
https://github.com/Tominator2/HEXtoIEEE-754

tofse 14. Mai 2018 12:50

AW: HexString to IEEE574 64 Bit
 
Ja, fand ich unbrauchbar, der funktioniert nicht mit 64Bit Hex.
Und ich habe es nicht verstanden, den anzupassen

himitsu 14. Mai 2018 12:56

AW: HexString to IEEE574 64 Bit
 
IEEE574 .... ähhhhhh 754?

Da INTEL/AMD/... alle IEEE754 verwenden und somit auch Delphi, muß hier garnichts gerechnet werden, sonden kann einfach via HexToBin umgewandelt und direkt in den Speicher der Double-Variable geschrieben werden.

tofse 14. Mai 2018 14:00

AW: HexString to IEEE574 64 Bit
 
Ich verstehe es leider nicht ganz, aber vom Prinzip her meinte ich das mit Optimieren :-)
http://docwiki.embarcadero.com/CodeE...thods_(Delphi)

Habe versucht, das so umzusetzen
Delphi-Quellcode:
  var hexstr,LStr2:WideString;
      Ergebnis:Extended;    
      Erg:^Extended;
...

  SetLength(LStr2, Length(hexstr) div 4);
  { Call the hexadecimal to binary conversion procedure. }
  HexToBin(PWideChar(hexstr), LStr2[1], Length(hexstr) div SizeOf(Char));
  Erg:=@LStr2[1];
  Ergebnis:=Erg^;
Wenn ich als Beispiel wieder das hier nehme E17A14AE47613740 kommt nicht 23.38 raus

himitsu 14. Mai 2018 15:01

AW: HexString to IEEE574 64 Bit
 
Extended = 80 Bit

gammatester 14. Mai 2018 15:02

AW: HexString to IEEE574 64 Bit
 
Ich nehme an, mit IEEE574 64 Bit meinst Du binary64 also double? Die eigeneliche Frage ist, was Dein Hex-String bedeuten soll. Ist das 'Big-Endian' oder 'Little-Endian'?. Als Beispiel für dezimal:

Gilt '123' -> 123 oder '123' -> 321 ?

IMO ist hier die Big-Endian-Interpretation die natürliche, hier der entsprechende Code aus meiner DAMath-Unit
Delphi-Quellcode:
type
  THexDblA = packed array[0..7] of byte; {Double  as array of bytes}

{---------------------------------------------------------------------------}
procedure Hex2Float(const hex: string; n: integer; var a: THexDblA; var code: integer);
  {-Common code for hex to float conversion, internal use only}
var
  i,j,m: integer;
  b: byte;
  c: char;
const
  c0  = ord('0');
  cal = ord('a') - 10;
  cau = ord('A') - 10;
begin
  if hex='' then code := -1
  else if (n=7) or (n=3) then begin
    if hex[1]='$' then m := 1 else m := 0;
    if length(hex)<>2*n+2+m then code := -2
    else begin
      b := 0;
      j := n; // LE: j=0, BE: j=n
      for i:=0 to 2*n+1 do begin
        inc(m);
        c := hex[m];
        if     (c>='0') and (c<='9') then b := (b shl 4) or ((ord(c)-c0 ) and $0F)
        else if (c>='A') and (c<='F') then b := (b shl 4) or ((ord(c)-cau) and $0F)
        else if (c>='a') and (c<='f') then b := (b shl 4) or ((ord(c)-cal) and $0F)
        else begin
          code := -4;
          exit;
        end;
        if odd(i) then begin
          a[j] := b;
          b := 0;
          dec(j); // LE: inc(j), BE: dec(j)
        end;
      end;
      code := 0;
    end;
  end
  else code := -3;
end;


{---------------------------------------------------------------------------}
procedure Hex2Dbl(const hex: string; var d: double; var code: integer);
  {-Convert big-endian hex string to double, leading $ is skipped, OK if code=0;}
  { hex must have 16 hex characters (17 if leading $), inverse of Dbl2Hex.}
var
  a: THexDblA;
  t: double absolute a;
begin
  Hex2Float(hex, 7, a, code);
  if code=0 then d := t;
end;
Aus Deinem Beispiel entnehme ich allerdings, dass Du wohl Little-Endian haben willst (in diesem Fall ändere die zwei markierten Stellen im Code). Das Testprogramm
Delphi-Quellcode:
program th2d;
{$Apptype console}

{Funktionen von oben, überschreibt Big-Endian}
var
  x: double;
  e: integer;
begin
  Hex2Dbl('E17A14AE47613740',x,e);
  writeln(x);
end.
gibt dann folgendes aus
Code:
D:\Work\DAMath>th2d.exe
 2.33800000000000E+0001


Alle Zeitangaben in WEZ +1. Es ist jetzt 19:41 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz