Recent

Author Topic: Converting long hexadecimal string to decimal string  (Read 3397 times)

arneolav

  • Full Member
  • ***
  • Posts: 197
Converting long hexadecimal string to decimal string
« on: January 08, 2025, 12:10:41 am »
I had to convert this long hex string: 2809E6CD040000F4 to decimal;
Result of Rapidtables: 2885090804517306612:

I found the following example in Stackoverflow:
  https://stackoverflow.com/questions/74417788/delphi-converting-long-hexadecimal-string-to-decimal-string


// Usage:  DecStr := ConvertToDecimal(s, '16' );
// It even works not only for hexadecimal (base 16) input but also for others.

I tested on some more long hex strings, and all correspond with Rapidtables

Code: Pascal  [Select][+][-]
  1.  
  2. type TArrayString= Array of String;
  3.  
  4. procedure MinLen( var s: String; iLen: Integer );
  5. begin
  6.  while Length( s )< iLen do s:= '0'+ s;
  7. end;
  8.  
  9.  
  10.  // Addition of multiple long numbers
  11. function Summe( aSummand: TArrayString ): String;
  12. var
  13.  iLenMax, iA, iPos, iSum, iAdvance: Integer;
  14.  c: Char;
  15. begin
  16.  result:= '0';
  17.  case Length( aSummand ) of
  18.    0: exit;  // Nothing to add at all
  19.    1: begin
  20.      result:= aSummand[Low( aSummand )];  // Sum equals the only summand
  21.      exit;
  22.    end;
  23.  end;
  24.  
  25.  // Find the longest text, then make all texts as long as the longest,
  26.  // so we can simply access an existing character at that position.
  27.  iLenMax:= 0;
  28.  for iA:= Low( aSummand ) to High( aSummand ) do begin
  29.    if Length( aSummand[iA] )> iLenMax then iLenMax:= Length( aSummand[iA] );
  30.  end;
  31.  for iA:= Low( aSummand ) to High( aSummand ) do MinLen( aSummand[iA], iLenMax );
  32.  MinLen( result, iLenMax );
  33.  
  34.  // All have the same length: process from the least significant digit
  35.  // (right) to the most significant digit (left).
  36.  for iPos:= iLenMax downto 1 do begin
  37.    // Manual addition: write all numbers in one row, then add single
  38.    // digits per row. Nobody will ever give this function so many
  39.    // summands that the sum of single digits will come near the Integer
  40.    // capacity.
  41.    iSum:= 0;
  42.    for iA:= Low( aSummand ) to High( aSummand ) do begin
  43.      Inc( iSum, Ord( aSummand[iA][iPos] )- $30 );  // Add digit from each number
  44.    end;
  45.    Inc( iSum, Ord( result[iPos] )- $30 );  // Also add result's digit from potential previous carry
  46.  
  47.    // Turn that Integer sum into text again, digit by digit
  48.    iAdvance:= 0;  // Exceeding the current position if we need to carry
  49.    while iSum> 0 do begin
  50.      c:= Chr( (iSum mod 10)+ $30 );  // Only the rightmost digit
  51.      if iPos- iAdvance< 1 then begin  // Outside the String?
  52.        result:= c+ result;  // Prepend
  53.      end else begin
  54.        result[iPos- iAdvance]:= c;  // Set new digit in overall sum
  55.      end;
  56.  
  57.      iSum:= iSum div 10;  // This digit has been process, go to next one
  58.      Inc( iAdvance );  // Not in the current position anymore, but processing potential carries
  59.    end;
  60.  end;
  61. end;
  62.  
  63.  
  64.    // Multiplication of two long numbers
  65. function Produkt( s1, s2: String ): String;
  66. var
  67.   iPos, iStep, iA, iNine: Integer;
  68.   aSummand, aStep: TArrayString;
  69. begin
  70.   // For each digit of one factor we will make a separate multiplication
  71.   SetLength( aSummand, Length( s1 ) );
  72.  
  73.   // This time it doesn't matter how long both numbers are: just again go
  74.   // from least significant digit (right) to most significant digit (left).
  75.   for iPos:= Length( s1 ) downto 1 do begin
  76.     iA:= Length( s1 )- iPos;  // Array index per digit
  77.     // As per our position the sum must be shifted by 10: first (rightmost)
  78.     // digit needs no shift (0), second needs one (10), third needs two (100)...
  79.     MinLen( aSummand[iA], iA );
  80.  
  81.     // Current digit
  82.     iStep:= Ord( s1[iPos] )- $30;
  83.     case iStep of
  84.       0: ;  // Multiplication by 0 always results in 0, an empty summand equals one of "0"
  85.       1: aSummand[iA]:= s2+ aSummand[iA];  // No multiplication needed, just prepend with factor
  86.     else
  87.       // Cheap multiplication: use addition with 2 to 9 times the same summand
  88.       SetLength( aStep, iStep );
  89.       for iNine:= 0 to iStep- 1 do aStep[iNine]:= s2;
  90.       aSummand[iA]:= Summe( aStep )+ aSummand[iA];  // Prepend sum, zeroes must be trailing
  91.     end;
  92.   end;
  93.  
  94.   // Now just add all sums that we got per digit
  95.   result:= Summe( aSummand );
  96. end;
  97.  
  98. // Convert base 2..36 long number into base 10 long number
  99. function ConvertToDecimal( sFrom: String; sBase: String= '16' ): String;
  100. var
  101.  sStep, sPos: String;
  102.  cFrom: Char;
  103. // a: TArrayString;
  104.  a: TArrayString;
  105. begin
  106.  SetLength( a, 2 );
  107.  a[0]:= '0';  // Overall sum = result
  108.  sPos:= '1';  // Current digit's power
  109.  while Length( sFrom )> 0 do begin  // Process least significant digit (right)
  110.    cFrom:= sFrom[Length( sFrom )];
  111.    case cFrom of  // For now at max base 36 is supported, which includes hexadecimal
  112.      '0'.. '9': sStep:= cFrom;  // Same as text
  113.      'A'.. 'Z': sStep:= IntToStr( Ord( cFrom )- $41+ 10 );  // Turn "B" into "11"
  114.    end;
  115.    a[1]:= Produkt( sPos, sStep );  // Multiply current digit's value by current position's power
  116.    a[0]:= Summe( a );  // Add both product and current overall result
  117.  
  118.    sPos:= Produkt( sPos, sBase );  // Increase power to next digit position
  119.    Delete( sFrom, Length( sFrom ), 1 );  // Remove rightmost digit
  120.  end;
  121.  result:= a[0];
  122. end;
  123.  
  124.  
  125. Good idea to test valid Hex in front:
  126. function HexIsValid(s: string): Boolean;
  127. var
  128.   i: integer;
  129. begin
  130.   Result := True;
  131.   for i := 1 to length(s) do
  132.     if not (s[i] in ['0'..'9','A'..'F','a'..'f']) then
  133.     begin
  134.       Result := False;
  135.       exit;
  136.     end;
  137. end;  
  138.  
Win 11, win64 , Lazarus 4.0RC3
Delphi/DevExpress

jollytall

  • Sr. Member
  • ****
  • Posts: 377
Re: Converting long hexadecimal string to decimal string
« Reply #1 on: January 08, 2025, 05:35:04 pm »
There is a good Wiki article with many options. Many support conversion to different bases:
https://wiki.freepascal.org/BigInteger

jamie

  • Hero Member
  • *****
  • Posts: 7405
Re: Converting long hexadecimal string to decimal string
« Reply #2 on: January 09, 2025, 01:21:29 am »
Interesting.

wouldn't using something that already exists in the libs be simpler or did I miss something?

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. begin
  3.   Caption :=Hex2Dec64('2809E6CD040000F4').ToString;
  4. end;                                                        
  5.  

Thet produces your number. include the "strUtils" unit.

jamie
The only true wisdom is knowing you know nothing

jamie

  • Hero Member
  • *****
  • Posts: 7405
Re: Converting long hexadecimal string to decimal string
« Reply #3 on: January 09, 2025, 01:28:17 am »
btw
 you don't need to use the "StrUtils" unit, I just find it has lots of goodies in it.


You can use StrToInt64('$'+'your hex number')

The only true wisdom is knowing you know nothing

 

TinyPortal © 2005-2018