Konwersja stringu w HEX na double

Konwersja stringu w HEX na double
CB
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 4 lata
  • Postów:13
0

Mam plik tekstowy w formacie WKB, w którym są zapisane 8 bajtowe liczby typu double.
Ale nie są zapisane po ludzku, czyli jak np. 123.45, tylko jako obraz bitowy liczby w.g. IEEE 754 (znak, cecha, mantysa, jak w asemblerze) w hexach, np:

The X co-ordinate is 2.0
000000000140000000000000004010000000000000
The Y-co-ordinate is 4.0
000000000140000000000000004010000000000000

Czy sa w Delphi jakieś funkcje biblioteczne, które mogą pomóc w konwersji takiej liczby na double?

cerrato
Moderator Kariera
  • Rejestracja:około 7 lat
  • Ostatnio:27 minut
  • Lokalizacja:Poznań
  • Postów:8797
0

CB
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 4 lata
  • Postów:13
0
cerrato napisał(a):

Tak na szybko - czy ten link rozwiązuje problem?
https://www.codeproject.com/Questions/99483/Convert-value-by-IEEE-754-protocol

Niestety, wygląda na to,że z Delphi nie ma dostępu do tego obiektu BitConverter

cerrato
ja chyba jeszcze zaspany jestem (w końcu jesteśmy przed południem), wybacz ;)
PD
  • Rejestracja:ponad 22 lata
  • Ostatnio:około 2 godziny
2

może to rozwiąże Twój problem:https://github.com/Tominator2/HEXtoIEEE-754


pozdrawiam
paweld
AK
Tak chorego kodu to dawno nie widziałem.
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
1

Oba powyższe rozwiązania bazują na liczbach pojedynczej precyzji.
Projekt z GitHub pewnie łatwiej będzie przerobić na double.

AK
  • Rejestracja:prawie 7 lat
  • Ostatnio:około miesiąc
  • Postów:3561
0

Wybaczcie pytanie delphistycznej blondynki.

To nie ma w D żadnych środków aby

  • wczytać hex string do tablicy bajtów
  • w/w tablicę zinterpretować jako double, rzutowanie, unia, czy jak tam nazywacie ...

Bo C to najlepszy język, każdy uczeń ci to powie
Zobacz pozostały 1 komentarz
AK
W normalnych językach programowania to kilka linii technicznego kodu, bez doktoratów. Biblioteka? Moze tak jak w JS, biblioteka do sklejania stringów albo mnożenia liczb?
flowCRANE
1. można na różne sposoby; 2. można rzutowaniem.
ME
To Delphi, tutaj tak się nie robi, tylko się instaluje komponent niewizualny TConvertHexString na formę a potem wywołuje tConvertHexString1.Convert(value) no i wypluwa wynik. Co nie znaczy, że w Pascalu nie da się napisać tych 3 linijek, ale to chodzi o mentalność bardziej. Takie rozleniwienie komponentami, czasem absurdalne.
flowCRANE
Bez przesady. Zresztą nawet jeśli byłaby to prawda, to mnogość komponentów wg mnie jest atutem, nie wadą. Natomiast jeśli deweloperzy każdą pierdołę implementowaliby w ten sposób (komponentami), to źle to by o nich świadczyło, a nie o samej technologii. No ale komponentowy mit pozostał i dalej potrafi śmieszyć. ;)
ME
Technologia jak technologia. Ważne to, jak się z niej korzysta, a ten mit jednak nie wziął się tak całkiem znikąd
vpiotr
  • Rejestracja:ponad 13 lat
  • Ostatnio:prawie 3 lata
1
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:12 minut
  • Lokalizacja:Tuchów
  • Postów:12171
0

A co z konwersją na UInt64 i rzutowaniem na Double? Można też Move zrobić zamiast rzutowania.

Edit: jednak nie – te koordynaty w postaci hex nie pasują rozmiarowo do szesnastkowego UInt64. Pozostaje po prostu mała funkcja, która przekonwertuje fragmenty ciągu na inty i zbuduje liczbę rzeczywistą. Czyli to co podał @Paweł Dmitruk – bez zbędnych warunków i komentarzy zostanie 10 linijek kodu.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 3x, ostatnio: flowCRANE
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 4 godziny
2

Jesteś pewny że to w ogóle dobre wartości? Po pierwsze mają po 21 bajtów co jest dość dziwnym rozmiarem dla typu liczbowego, po drugie podałeś dwa razy ten sam ciąg a mają one niby reprezentować różne wartości

edit: wygooglałem wklejony ciąg do googla

https://mariadb.com/kb/en/well-known-binary-wkb-format/

zgubiłeś pogrubienia:

  • The first byte indicates the byte order. 00 for big endian, or 01 for little endian.
  • The next 4 bytes indicate the geometry type. Values from 1 to 7 indicate whether the type is Point, LineString, Polygon, MultiPoint, MultiLineString, MultiPolygon, or GeometryCollection respectively.
  • The 8-byte floats represent the co-ordinates.

Czyli tylko "4000000000000000" reprezentuje "2.0" a "4010000000000000" reprezentuje "4.0"
Nie znam pascala (ostatni kod w nim pisałem jakieś 16 lat temu) ale pół minuty w googlach wystarczy żeby znaleźć:

https://ideone.com/GDQZfu

Kopiuj
uses sysutils;

var
  xi : int64;
  yi : int64;
  x: double absolute xi;
  y: double absolute yi;
begin
	xi := StrToInt64('$4000000000000000');
	yi := StrToInt64('$4010000000000000');
	writeLn(x); // 2.0
	writeLn(y); // 4.0
end.

"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 8x, ostatnio: obscurity
flowCRANE
O to właśnie chodzi.
CB
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 4 lata
  • Postów:13
0

Dziękuję za pomoc.
Dla potomności pozostawiam elegancką funkcję:

Kopiuj
function HexToDouble(txt:String):Double;
var
  xi : int64;
  x: double absolute xi;
begin
  xi := StrToInt64('$'+txt);
  result:=(x);
end;

Sposób użycia: HexToDouble('4000000000000000') da wynik 2.0

edytowany 1x, ostatnio: flowCRANE
AK
Coś mi to nie gra, przynajmniej jeśli w hexie jest to, co POWINNO być.
obscurity
@AnyKtokolwiek: a co tam powinno być? @coder-bis: możesz od razu dać xi: int64 absolute Result jak w przykładzie poniżej, wtedy nie musisz już przepisywać x do result
AK
wykładnik, mantysa? ja tego nie widzę tutaj. Ciąg bajtów pod floatem to nie int odpowiedniej długości.
obscurity
to jest w hexie - masz 0x4000000000000000 czyli znak 0, wykładnik 10000000000b, mantysa 0b czyli 1 = 1 * 1 * 2^1 = 2.0
flowCRANE
Moderator Delphi/Pascal
  • Rejestracja:ponad 13 lat
  • Ostatnio:12 minut
  • Lokalizacja:Tuchów
  • Postów:12171
1

Dziwnie to wygląda. Masz przykład funkcji konwertujących we Free Pascalu – sprawdź czy w Delphi zadziała:

Kopiuj
function DoubleToString(const AValue: Double): String; inline;
var
  Cast: Int64 absolute AValue;
begin
  Result := '$' + HexStr(Cast, SizeOf(Cast) * 2);
end;

function StringToDouble(const AValue: String): Double; inline;
var
  Cast: Int64 absolute Result;
  Dummy: Integer;
begin
  Val(AValue, Cast, Dummy);
end;

Test użycia:

Kopiuj
var
  ValueAsString: String;
  ValueAsDouble: Double = Pi;
begin
  WriteLn('Double: "', ValueAsDouble:2:16, '"');

  ValueAsString := DoubleToString(ValueAsDouble);
  WriteLn('String: "', ValueAsString, '"');

  ValueAsDouble := 0;
  WriteLn('Double: "', ValueAsDouble:2:16, '"');

  ValueAsDouble := StringToDouble(ValueAsString);
  WriteLn('Double: "', ValueAsDouble:2:16, '"');
end.

I wyjście konsoli:

Kopiuj
Double: "3.1415926535897931"  // wartość początkowa – tutaj Pi
String: "$400921FB54442D18"   // ciąg znaków po konwersji liczby zmiennoprzecinkowej
Double: "0.0000000000000000"  // wyzerowana wartość (żeby nie było że optymalizator wyciął numer)
Double: "3.1415926535897931"  // wartość po konwersji ciągu na liczbę zmiennoprzecinkową

Perfekcyjne odwzorowanie poprzedniego stanu.


Pracuję nad własną, arcade'ową, docelowo komercyjną grą z gatunku action/adventure w stylu retro (pixel art), programując silnik i powłokę gry od zupełnych podstaw, przy użyciu Free Pascala i SDL3. Więcej informacji znajdziesz na moim mikroblogu.
edytowany 1x, ostatnio: flowCRANE
obscurity
przecież to dokładnie to samo tylko zamienione "StrToInt64" na "Val"
AK
Test dla liczb z wykładnikiem zero. A dla innych?
flowCRANE
@obscurity: ale w dwie strony i z przykładem użycia, niech zostanie dla potomnych. @AnyKtokolwiek: każda liczba przejdzie – w końcu i tak jest rzutowana na Int64, więc nie ma znaczenia, nawet jeśli będzie tam NaN czy Infinity.
obscurity
@AnyKtokolwiek: tam nie ma wykładnika zero. Tu https://gregstoll.dyndns.org/~gregstoll/floattohex/ możesz sobie zobaczyć jak double jest zakodowany na bitach
CB
  • Rejestracja:ponad 7 lat
  • Ostatnio:około 4 lata
  • Postów:13
0

Skoro jesteście tak chętni do pomocy, to może pomożecie mi w pracy detektywistycznej, rozkminienia tego formatu WKB
W pliku dostaję coś takiego:

0
0103000020840800000100000012000000B93313FCCDC61D418692C981207423415342B0EAFFC31D4140DD40A937742341728BF9091DC11D4138D7307B4F7423413D0D18A[....]

Z tego co sam doszedłem,
0 - zignorować
w stringu dwa pierwsze znaki 01 - to oznacza litle endian
0300 0020 8408 0000 0100 0000 1200 0000 - następne 32 znaki to jakiś nagłówek, bo we wszystkich plikach się powtarza podobny. W nim zgaduję, że 0100 - oznacza, że w pliku jest jakiś wielokąt (to się zgadza, powinna być granica działki), 1200 - to pewnie liczba wierzchołków ($12 czyli 18 wierzchołków)
dalej powinny być wspólrzędne, po kolei x y x y 18 razy
Zatem pierwsza liczba to B93313FCCDC61D41, ale jej konwersja ww. funkcją daje wynik ~-3,67 E-33, czyli bez sensu. Powinna być rozsądna liczba rzędu paruset tysięcy.
Macie jakiś pomysł co może być źle? Może ze względu na little endian trzeba poprzestawiać któreś bajty?

AK
Zgadywanka bez założeń? To by nie miało sensu. Ale ty chyba znasz jakieś założenia, a my nie, mamy zgadywać?
obscurity
  • Rejestracja:około 6 lat
  • Ostatnio:około 4 godziny
1

Tak przy 01 masz little endian czyli musisz odwrócić wszystkie bajty, przykładowo B93313FCCDC61D41 = 411DC6CDFC1333B9 - jako float by to było 487859.49616699998 ale nie wiem czy to prawidłowy fragment.
Nie ma tu co zgadywać - WKB to standard - sprawdź czy ten tool online potrafi to rozkodować:
https://rodic.fr/blog/online-conversion-between-geometric-formats/
korzysta z bilbioteki w js https://github.com/cschwarz/wkx
Może uda Ci się znaleźć coś do delphi, ale jeśli nie to zawsze możesz się wspomóc źródłami tej biblioteki żeby napisać własny kod

Tu masz jakąś funkcję do odwracania bajtów jako wstawka asm:

Kopiuj
function BSwap64(I: QWORD): QWORD; { inline; }
asm
        MOV     EDX,[EAX]
        MOV     EAX,[EAX+4]
        BSWAP   EAX
        BSWAP   EDX
end;

Swoją drogą strasznie głupi standard który marnuje bajt na zapisanie informacji o endianness zamiast go po prostu... ustandaryzować


"A car won't take your job, another horse driving a car will." - Horse influencer, 1910
edytowany 2x, ostatnio: obscurity
CB
Dzięki, po odwróceniu bajtów działa

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.