Liczba 128-bitowa do bufora i odwrotnie

1

Jest sobie Edit, do którego wpisuję dziesiętnie liczbę w zakresie 0..2^128-1 (128 bitową).
Jak przekonwertować tak dużą liczbę do postaci binarnej, tzn. zapisać w 16-bajtowym buforze?

Jak zrobić konwersję odwrotną?

2

Wykorzystaj np. GMP (powinno się udać bez problemu dokonać konwersji z x10 do x2).

0

Dzięki! Wykorzystałem tą bibliotekę GMP, oczywiście wspomagając się wrapperem dla Delphi (https://code.google.com/archive/p/gmp-wrapper-for-delphi/downloads).

uses gmp_lib, gmp_obj;

var
  s: AnsiString;
  i: mpz_t;
  buf: array [0..15] of byte;
  count: mp_size_t;
begin
  //s:='340282366920938463463374607431760000000';
  s := '4584946418820579326'; //łańcuch do konwersji (niezbyt długi, żeby można było zweryfikować wynik w kalkulatorze)
  mpz_init_set_str(i, PAnsiChar(s), 10); //konwersja stringa do typu mpz_t
  mpz_export(@buf, @count, -1, 1, 0, 0, i); //konwersja (little endian) typu mpz_t do bufora "buf" (istotne tylko początkowych "count" bajtów!)
  if count < 16 then
    FillChar(buf[count], 16 - count, 0); //wyzerowanie nieistotnych bajtów
end;
 
1

I jeszcze uzupełniam o konwersję odwrotną z bufora (128b) do stringa, tak więc po ubraniu w procedurę i funkcję wygląda to tak (dla potomnych):

 
uses gmp_lib, gmp_obj;

type
 TBuf128Bit = array [0..15] of Byte; //bufor 128-bitowy
 
procedure StringToBuf128Bit(s: AnsiString; var buf: TBuf128Bit); //konwersja liczby dziesiętnej w stringu do bufora 128-bitowego (little endian)
var
  i: mpz_t;
  count: mp_size_t;
begin
  mpz_init_set_str(i, PAnsiChar(s), 10); //konwersja liczby dziesiętnej w stringu do zmiennej "i" typu "mpz_t"
  mpz_export(@buf, @count, -1, 1, 0, 0, i); //konwersja (little endian) zmiennej "i" typu "mpz_t" do bufora "buf" (istotne tylko początkowych "count" bajtów!)
  if count < 16 then
    FillChar(buf[count], 16 - count, 0); //!!! wyzerowanie nieistotnych bajtów
  mpz_clear(i); //zwolnienie "i"
end;

function Buf128BitToString(buf: TBuf128Bit): AnsiString; //konwersja bufora 128-bitowego (little endian) do liczby w stringu (zapis dziesiętny)
 Var
  i: mpz_t;
begin
  mpz_init(i); //inicjalizacja zmiennej
  mpz_import(i, 16, -1, 1, 0, 0, @buf); //konwersja bufora "buf" (little endian) do zmiennej "i" typu "mpz_t"
  result := mpz_get_str(nil, 10, i); //konwersja zmiennej "i" typu "mpz_t" do liczby w stringu (zapis dziesiętny)
  mpz_clear(i); //zwolnienie "i"
end;

procedure TForm1.Button1Click(Sender: TObject); //test konwersji w obie strony
Var
  buf: TBuf128Bit;
  s_in, s_out: AnsiString;
begin
  //s_in:= '340282366920938463463374607431768211455'; //max na 128 bitach (2^128-1)
  s_in := '4584946418820579326';
  StringToBuf128Bit(s_in, buf);
  s_out := Buf128BitToString(buf);
 ShowMessage(String(s_out)); //s_out = s_in
end;
0

Dodam jeszcze, że można też sprawdzić, czy konwertowany łańcuch nie przekracza maksymalnej wartości 2^128-1, czyli po zamianie procedury "StringToBuf128Bit" na funkcję:

function TryStringToBuf128Bit(s: AnsiString; var buf: TBuf128Bit): boolean; //konwersja liczby dziesiętnej w stringu do bufora 128-bitowego (little endian)
var
  i: mpz_t;
  count: mp_size_t;
begin
  mpz_init_set_str(i, PAnsiChar(s), 10); //konwersja liczby dziesiętnej w stringu do zmiennej "i" typu "mpz_t"
  mpz_export(@buf, @count, -1, 1, 0, 0, i); //konwersja (little endian) zmiennej "i" typu "mpz_t" do bufora "buf" (istotne tylko początkowych "count" bajtów!)
  if count <= 16 then //jeśli ilość bajtów potrzebna do zapisu binarnego liczby nie jest większa od 16 (liczba w zakresie 128-bitów)
  begin
    if count < 16 then
      FillChar(buf[count], 16 - count, 0); //!!! wyzerowanie nieistotnych bajtów    
    result := true; //liczba w stringu w zakresie do 128-bitów (2^128-1)
  end
  else
    result := false; //liczba w stringu ponad zakres 128-bitów
  mpz_clear(i); //zwolnienie "i"
end; 

1 użytkowników online, w tym zalogowanych: 0, gości: 1