Recent

Author Topic: Standart function for length of decimal number  (Read 3654 times)

Josh

  • Hero Member
  • *****
  • Posts: 1424
Re: Standart function for length of decimal number
« Reply #30 on: October 18, 2025, 02:39:08 pm »
moded it to use the De Bruijn Branchless Method, soshould inline ok
done a test on 1,000,000,000 large int64 on my little lappy took 2481 getclock64 ticks

Code: Pascal  [Select][+][-]
  1. unit FastDigits;
  2. {$mode objfpc}{$H+}
  3.  
  4. interface
  5.  
  6. function DecimalLength(const x:Int64):LongInt;overload;
  7. function DecimalLength(const x:QWord):LongInt;overload;
  8. function DecimalLength(const x:Int32):LongInt;overload;
  9. function DecimalLength(const x:Cardinal):LongInt;overload;
  10. function DecimalLength(const x:Word):LongInt;overload;
  11. function DecimalLength(const x:SmallInt):LongInt;overload;
  12. function DecimalLength(const x:ShortInt):LongInt;overload;
  13. function DecimalLength(const x:Byte):LongInt;overload;
  14.  
  15. implementation
  16.  
  17. const
  18.   POW10_64:array[0..19] of QWord=(1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000,100000000000000,1000000000000000,10000000000000000,100000000000000000,1000000000000000000,10000000000000000000);
  19.  
  20.   POW10_32:array[0..10] of LongWord=(1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,4294967295);
  21.  
  22.   // De Bruijn Branchless Method
  23.  
  24.   deBruijn64:array[0..63] of Byte=(0,1,2,53,3,7,54,27,4,38,41,8,34,55,48,28,62,5,39,46,44,42,22,9,24,35,59,56,49,18,29,11,63,52,6,26,37,40,33,47,61,45,43,21,23,58,17,10,51,25,36,32,60,20,57,16,50,31,19,15,30,14,13,12);
  25.  
  26.   deBruijn32:array[0..31] of Byte=(0,1,28,2,29,14,24,3,30,22,20,15,25,17,4,8,31,27,13,23,21,19,16,7,26,12,18,6,11,5,10,9);
  27.  
  28. function BitLength64(n:QWord):LongInt;inline;
  29. var t:QWord;
  30. begin
  31.   t:=n;
  32.   t:=t or (t shr 1);
  33.   t:=t or (t shr 2);
  34.   t:=t or (t shr 4);
  35.   t:=t or (t shr 8);
  36.   t:=t or (t shr 16);
  37.   t:=t or (t shr 32);
  38.   Result:=deBruijn64[((t-(t shr 1))*$022FDD63CC95386D) shr 58]+1;
  39. end;
  40.  
  41. function BitLength32(n:LongWord):LongInt;inline;
  42. var t:LongWord;
  43. begin
  44.   t:=n;
  45.   t:=t or (t shr 1);
  46.   t:=t or (t shr 2);
  47.   t:=t or (t shr 4);
  48.   t:=t or (t shr 8);
  49.   t:=t or (t shr 16);
  50.   Result:=deBruijn32[((t-(t shr 1))*$077CB531) shr 27]+1;
  51. end;
  52.  
  53. function DecimalLength64(const n:QWord):LongInt;inline;
  54. var bits,guess:LongInt;
  55. begin
  56.   if n<10 then Exit(1);
  57.   bits:=BitLength64(n);
  58.   guess:=(bits*1233) shr 12;
  59.   if n>=POW10_64[guess] then Inc(guess);
  60.   Result:=guess;
  61. end;
  62.  
  63. function DecimalLength32(n:LongWord):LongInt;inline;
  64. var bits,guess:LongInt;
  65. begin
  66.   if n<10 then Exit(1);
  67.   bits:=BitLength32(n);
  68.   guess:=(bits*1233) shr 12;
  69.   if n>=POW10_32[guess] then Inc(guess);
  70.   Result:=guess;
  71. end;
  72.  
  73. function DecimalLength(const x:Int64):LongInt;overload;
  74. begin
  75.   if x<0 then Result:=DecimalLength64(QWord(-x))
  76.   else
  77.     Result:=DecimalLength64(QWord(x));
  78. end;
  79.  
  80. function DecimalLength(const x:QWord):LongInt;overload;
  81. begin
  82.   Result:=DecimalLength64(x);
  83. end;
  84.  
  85. function DecimalLength(const x:Int32):LongInt;overload;
  86. begin
  87.   if x<0 then Result:=DecimalLength32(LongWord(-x))
  88.   else
  89.     Result:=DecimalLength32(LongWord(x));
  90. end;
  91.  
  92. function DecimalLength(const x:Cardinal):LongInt;overload;
  93. begin
  94.   Result:=DecimalLength32(x);
  95. end;
  96.  
  97. function DecimalLength(const x:Word):LongInt;overload;
  98. begin
  99.   if x<10 then Exit(1)
  100.   else
  101.     if x<100 then Exit(2)
  102.     else
  103.       if x<1000 then Exit(3)
  104.       else
  105.         Exit(4);
  106. end;
  107.  
  108. function DecimalLength(const x:SmallInt):LongInt;overload;
  109. begin
  110.   if x<0 then Exit(1+DecimalLength(-x));
  111.   if x<10 then Exit(1)
  112.   else
  113.     Exit(2);
  114. end;
  115.  
  116. function DecimalLength(const x:ShortInt):LongInt;overload;
  117. begin
  118.   if x<0 then Exit(1+DecimalLength(-x));
  119.   if x<10 then Exit(1)
  120.   else
  121.     Exit(2);
  122. end;
  123.  
  124. function DecimalLength(const x:Byte):LongInt;overload;
  125. begin
  126.   if x<10 then Exit(1)
  127.   else if x<100 then Exit(2)
  128.   else
  129.     Exit(3);
  130. end;
  131.  
  132. end.
  133.  
« Last Edit: October 18, 2025, 03:01:25 pm by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

LemonParty

  • Sr. Member
  • ****
  • Posts: 360
Re: Standart function for length of decimal number
« Reply #31 on: October 18, 2025, 04:12:45 pm »
Here I combined both methods to reach the best performance:
Code: Pascal  [Select][+][-]
  1. function DecimalLength(u: UInt32): SizeUInt;inline;
  2. const
  3.   CTable: array [0..32] of UInt64 = (
  4.     4294967296,
  5.     4294967296,  8589934582,  8589934582,  8589934582,
  6.     12884901788, 12884901788, 12884901788, 17179868184,
  7.     17179868184, 17179868184, 21474826480, 21474826480,
  8.     21474826480, 21474826480, 25769703776, 25769703776,
  9.     25769703776, 30063771072, 30063771072, 30063771072,
  10.     34349738368, 34349738368, 34349738368, 34349738368,
  11.     38554705664, 38554705664, 38554705664, 41949672960,
  12.     41949672960, 41949672960, 42949672960, 42949672960
  13.   );
  14. begin
  15.   Result:= ( u + CTable[ UInt8( BsrDWord( u )+1 ) ] ) shr 32;
  16. end;
  17.  
  18. function DecimalLength(i: Int32): SizeUInt;inline;
  19. begin
  20.   Result:= ord(i < 0) + DecimalLength(UInt32(Abs(i)));
  21. end;
  22.  
  23. function DecimalLength(u: UInt64): SizeUInt;inline;
  24. begin
  25.   if u <= High(UInt32) then
  26.     Result:= DecimalLength(UInt32(u))
  27.   else case u of
  28.     High(UInt32)+1..9999999999: Result:= 10;
  29.     10000000000..99999999999: Result:= 11;
  30.     100000000000..999999999999: Result:= 12;
  31.     1000000000000..9999999999999: Result:= 13;
  32.     10000000000000..99999999999999: Result:= 14;
  33.     100000000000000..999999999999999: Result:= 15;
  34.     1000000000000000..9999999999999999: Result:= 16;
  35.     10000000000000000..99999999999999999: Result:= 17;
  36.     100000000000000000..999999999999999999: Result:= 18;
  37.     1000000000000000000..9999999999999999999: Result:= 19;
  38.     else Result:= 20;
  39.   end;
  40. end;
  41.  
  42. function DecimalLength(i: Int64): SizeUInt;inline;
  43. begin
  44.   Result:= ord(i < 0) + DecimalLength(UInt64(Abs(i)));
  45. end;
  46.  
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Kays

  • Hero Member
  • *****
  • Posts: 624
  • Whasup!?
    • KaiBurghardt.de
Re: Standard function for length of decimal number
« Reply #32 on: October 18, 2025, 10:00:27 pm »
Fortunately that has been researched already. […]
And it has been asked and answered before: simple problem: count digits of number
Is there a [standard] function that [returns the] number of decimal digits in [a] signed/unsigned integer?
Neither ISO 7185 or 10206 define such (so there’s no formally standardized function); you can still write a one‑liner just with onboard means though:
Code: Pascal  [Select][+][-]
  1. type
  2.         natural = 1..maxInt;
  3.         wholeNumber = 0..maxInt;
  4. function decimalDigitCount(n: wholeNumber): natural;
  5.         begin
  6.                 decimalDigitCount := trunc(ln(n + ord(n = 0)) / ln(10)) + 1
  7.         end;
Yours Sincerely
Kai Burghardt

MathMan

  • Sr. Member
  • ****
  • Posts: 434
Re: Standard function for length of decimal number
« Reply #33 on: October 18, 2025, 10:30:51 pm »
Fortunately that has been researched already. […]
And it has been asked and answered before: simple problem: count digits of number
Is there a [standard] function that [returns the] number of decimal digits in [a] signed/unsigned integer?
Neither ISO 7185 or 10206 define such (so there’s no formally standardized function); you can still write a one‑liner just with onboard means though:
Code: Pascal  [Select][+][-]
  1. type
  2.         natural = 1..maxInt;
  3.         wholeNumber = 0..maxInt;
  4. function decimalDigitCount(n: wholeNumber): natural;
  5.         begin
  6.                 decimalDigitCount := trunc(ln(n + ord(n = 0)) / ln(10)) + 1
  7.         end;

OMG - and I even took part in that discussion then, shame on me  >:(

Of course the one liner above does the trick, but it is really slow compared to some of the other solutions presented here. And even slower if you happen to work on a system that needs SoftFloat.

Nevertheless I learned something during the discussion now. The case statement variants are (to me) suprisingly fast considering the code that is produced. But due to the code size I'd be inclined to disable inline there and in that case both variants fall back behind the fully table driven implementation (also with inline disabled).

jamie

  • Hero Member
  • *****
  • Posts: 7306
Re: Standart function for length of decimal number
« Reply #34 on: October 19, 2025, 01:03:45 am »
This is my version, short and simple.
Code: Pascal  [Select][+][-]
  1. unction HowManyDigits(aInput:QWord):Integer; Inline;
  2. begin
  3.   Result:=1;
  4.   While aInput > 9 do
  5.     begin
  6.       Inc(Result);
  7.       aInput := aInput div 10;
  8.     end;
  9. end;                              
  10.  
and the ASM output.
Code: Pascal  [Select][+][-]
  1. 000000010003484F 41B801000000             mov r8d,$00000001
  2. 0000000100034855 EB1C                     jmp +$1C    # $0000000100034873 Button1Click+67 unit1.pas:83
  3. 0000000100034857 90                       nop
  4. 0000000100034858 4183C001                 add r8d,$01
  5. 000000010003485C 4889CA                   mov rdx,rcx
  6. 000000010003485F 48B8CDCCCCCCCCCCCCCC     mov rax,$CCCCCCCCCCCCCCCD
  7. 0000000100034869 48F7E2                   mul rdx
  8. 000000010003486C 48C1EA03                 shr rdx,$03
  9. 0000000100034870 4889D1                   mov rcx,rdx
  10. 0000000100034873 4883F909                 cmp rcx,$09
  11. 0000000100034877 77DF                     jnbe -$21    # $0000000100034858 Button1Click+40 unit1.pas:83
  12.  
The only true wisdom is knowing you know nothing

bytebites

  • Hero Member
  • *****
  • Posts: 755
Re: Standart function for length of decimal number
« Reply #35 on: October 19, 2025, 09:06:32 am »
Code: Pascal  [Select][+][-]
  1. function DecLenif(i: QWord): integer;
  2. begin
  3.   if i<10000000 then
  4.          if i<10 then exit( 1 )
  5.     else if i<100 then exit( 2 )
  6.     else if i<1000 then exit( 3 )
  7.     else if i<10000 then exit( 4 )
  8.     else if i<100000 then exit( 5 )
  9.     else if i<1000000 then exit( 6 )
  10.     else exit( 7 )
  11.     else if i<10000000000000 then
  12.          if i<100000000 then exit( 8 )
  13.     else if i<1000000000 then exit( 9 )
  14.     else if i<10000000000 then exit( 10 )
  15.     else if i<100000000000 then exit( 11 )
  16.     else if i<1000000000000 then exit( 12 )
  17.     else exit( 13 )
  18.     else if i<100000000000000 then exit( 14 )
  19.     else if i<1000000000000000 then exit( 15 )
  20.     else if i<10000000000000000 then exit( 16 )
  21.     else if i<100000000000000000 then exit( 17 )
  22.     else if i<1000000000000000000 then exit( 18 )
  23.     else if i<10000000000000000000 then exit( 19 )
  24.   else exit( 20 );
  25. end;  

Thaddy

  • Hero Member
  • *****
  • Posts: 18321
  • Here stood a man who saw the Elbe and jumped it.
Re: Standart function for length of decimal number
« Reply #36 on: October 19, 2025, 12:48:49 pm »
That is what the case loop does, exiting when ready. The lookup from mathman is much faster, though.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

BrunoK

  • Hero Member
  • *****
  • Posts: 716
  • Retired programmer
Re: Standart function for length of decimal number
« Reply #37 on: October 19, 2025, 01:36:25 pm »
Hey guys, if you want to check/benchmark your new routines, insert and test them with the program supplied by avk in post.

ASerge

  • Hero Member
  • *****
  • Posts: 2464
Re: Standart function for length of decimal number
« Reply #38 on: October 19, 2025, 06:33:16 pm »
The tests above are for QWord.
FPC 3.2.2 x64, Windows.
There is no range/overflow check. Optimization level 3.
Code: Pascal  [Select][+][-]
  1. {$MODE OBJFPC}
  2. {$LONGSTRINGS ON}
  3. {$IFDEF WINDOWS}
  4.   {$APPTYPE CONSOLE}
  5. {$ENDIF}
  6.  
  7. uses SysUtils, DateUtils;
  8.  
  9. type
  10.   TDecimalLength64 = function(AValue: QWord): Integer;
  11.  
  12. var
  13.   GValues64: array of QWord = nil;
  14.  
  15. procedure Measure64(Func: TDecimalLength64; const Desc: string);
  16. const
  17.   CTimes = 1000;
  18. var
  19.   i: SizeInt;
  20.   Start: TDateTime;
  21.   Value: QWord;
  22. begin
  23.   Write(Desc, '': 30 - Length(Desc));
  24.   Start := Time;
  25.   for i := 1 to CTimes do
  26.     for Value in GValues64 do
  27.       Func(Value);
  28.   WriteLn(MilliSecondsBetween(Start, Time), ' msec');
  29. end;
  30.  
  31. procedure InitGValues64;
  32. const
  33.   CCount = 10000;
  34. var
  35.   i: SizeInt;
  36. begin
  37.   Randomize;
  38.   SetLength(GValues64, CCount);
  39.   for i := 0 to CCount - 1 do
  40.     GValues64[i] := Random(High(Int64));
  41. end;
  42.  
  43. { Bytebits }
  44.  
  45. function BytebitsDecLenIf(i: QWord): Integer;
  46. begin
  47.   if i<10000000 then
  48.          if i<10 then exit( 1 )
  49.     else if i<100 then exit( 2 )
  50.     else if i<1000 then exit( 3 )
  51.     else if i<10000 then exit( 4 )
  52.     else if i<100000 then exit( 5 )
  53.     else if i<1000000 then exit( 6 )
  54.     else exit( 7 )
  55.     else if i<10000000000000 then
  56.          if i<100000000 then exit( 8 )
  57.     else if i<1000000000 then exit( 9 )
  58.     else if i<10000000000 then exit( 10 )
  59.     else if i<100000000000 then exit( 11 )
  60.     else if i<1000000000000 then exit( 12 )
  61.     else exit( 13 )
  62.     else if i<100000000000000 then exit( 14 )
  63.     else if i<1000000000000000 then exit( 15 )
  64.     else if i<10000000000000000 then exit( 16 )
  65.     else if i<100000000000000000 then exit( 17 )
  66.     else if i<1000000000000000000 then exit( 18 )
  67.     else if i<10000000000000000000 then exit( 19 )
  68.   else exit( 20 );
  69. end;
  70.  
  71. { Jamie }
  72.  
  73. function JamieHowManyDigits(aInput:QWord): Integer;
  74. begin
  75.   Result:=1;
  76.   While aInput > 9 do
  77.     begin
  78.       Inc(Result);
  79.       aInput := aInput div 10;
  80.     end;
  81. end;
  82.  
  83. { Keys }
  84.  
  85. function KeysDecimalDigitCount(n: QWord): Integer;
  86. begin
  87.   Result := Trunc(Ln(n + Ord(n = 0)) / Ln(10)) + 1;
  88. end;
  89.  
  90. { LemonParty }
  91.  
  92. function LemonPartyDecimalLength32(u: UInt32): Integer; inline;
  93. const
  94.   CTable: array [0..32] of UInt64 = (
  95.     4294967296,
  96.     4294967296,  8589934582,  8589934582,  8589934582,
  97.     12884901788, 12884901788, 12884901788, 17179868184,
  98.     17179868184, 17179868184, 21474826480, 21474826480,
  99.     21474826480, 21474826480, 25769703776, 25769703776,
  100.     25769703776, 30063771072, 30063771072, 30063771072,
  101.     34349738368, 34349738368, 34349738368, 34349738368,
  102.     38554705664, 38554705664, 38554705664, 41949672960,
  103.     41949672960, 41949672960, 42949672960, 42949672960
  104.   );
  105. begin
  106.   Result:= ( u + CTable[ UInt8( BsrDWord( u )+1 ) ] ) shr 32;
  107. end;
  108.  
  109. function LemonPartyDecimalLength64(u: QWord): Integer;
  110. begin
  111.   if u <= High(UInt32) then
  112.     Result:= LemonPartyDecimalLength32(UInt32(u))
  113.   else case u of
  114.     High(UInt32)+1..9999999999: Result:= 10;
  115.     10000000000..99999999999: Result:= 11;
  116.     100000000000..999999999999: Result:= 12;
  117.     1000000000000..9999999999999: Result:= 13;
  118.     10000000000000..99999999999999: Result:= 14;
  119.     100000000000000..999999999999999: Result:= 15;
  120.     1000000000000000..9999999999999999: Result:= 16;
  121.     10000000000000000..99999999999999999: Result:= 17;
  122.     100000000000000000..999999999999999999: Result:= 18;
  123.     1000000000000000000..9999999999999999999: Result:= 19;
  124.     else Result:= 20;
  125.   end;
  126. end;
  127.  
  128. { Josh }
  129.  
  130. function JoshBitLength64(n:QWord): Integer; inline;
  131. const
  132.   deBruijn64:array[0..63] of Byte=(0,1,2,53,3,7,54,27,4,38,41,8,34,55,48,28,62,5,39,46,44,42,22,9,24,35,59,56,49,18,29,11,63,52,6,26,37,40,33,47,61,45,43,21,23,58,17,10,51,25,36,32,60,20,57,16,50,31,19,15,30,14,13,12);
  133. var t:QWord;
  134. begin
  135.   t:=n;
  136.   t:=t or (t shr 1);
  137.   t:=t or (t shr 2);
  138.   t:=t or (t shr 4);
  139.   t:=t or (t shr 8);
  140.   t:=t or (t shr 16);
  141.   t:=t or (t shr 32);
  142.   Result:=deBruijn64[((t-(t shr 1))*$022FDD63CC95386D) shr 58]+1;
  143. end;
  144.  
  145. function JoshDecimalLength64(n:QWord): Integer;
  146. const
  147.   POW10_64:array[0..19] of QWord=(1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000,10000000000,100000000000,1000000000000,10000000000000,100000000000000,1000000000000000,10000000000000000,100000000000000000,1000000000000000000,10000000000000000000);
  148. var bits,guess:LongInt;
  149. begin
  150.   if n<10 then Exit(1);
  151.   bits:=JoshBitLength64(n);
  152.   guess:=(bits*1233) shr 12;
  153.   if n>=POW10_64[guess] then Inc(guess);
  154.   Result:=guess;
  155. end;
  156.  
  157. { Thaddy }
  158.  
  159. function ThaddyDecLength(i: QWord): Integer;
  160. begin
  161.   case i of
  162.   0..9:result := 1;
  163.   10..99: result := 2;
  164.   100..999:result := 3;
  165.   1000..9999:result := 4;
  166.   10000..99999:result := 5;
  167.   100000..999999:result := 6;
  168.   1000000..9999999:result := 7;
  169.   10000000..99999999:result := 8;
  170.   100000000..999999999:result := 9;
  171.   1000000000..9999999999:result := 10;
  172.   10000000000..99999999999:result := 11;
  173.   100000000000..999999999999:result := 12;
  174.   1000000000000..9999999999999:result := 13;
  175.   10000000000000..99999999999999:result := 14;
  176.   100000000000000..999999999999999:result := 15;
  177.   1000000000000000..9999999999999999:result := 16;
  178.   10000000000000000..99999999999999999:result := 17;
  179.   100000000000000000..999999999999999999:result := 18;
  180.   1000000000000000000..9999999999999999999:result := 19
  181.   else result := 20;
  182.   end;
  183. end;
  184.  
  185. begin
  186.   InitGValues64;
  187.   Measure64(@LemonPartyDecimalLength64, 'LemonPartyDecimalLength64');
  188.   Measure64(@ByteBitsDecLenIf, 'ByteBitsDecLenIf');
  189.   Measure64(@JoshDecimalLength64, 'JoshDecimalLength64');
  190.   Measure64(@ThaddyDecLength, 'ThaddyDecLength');
  191.   Measure64(@JamieHowManyDigits, 'JamieHowManyDigits');
  192.   Measure64(@KeysDecimalDigitCount, 'KeysDecimalDigitCount');
  193.   Writeln;
  194.   Write('Press Enter to close...');
  195.   Readln;
  196. end.

Result:
Code: Text  [Select][+][-]
  1. LemonPartyDecimalLength64     79 msec
  2. ByteBitsDecLenIf              91 msec
  3. JoshDecimalLength64           91 msec
  4. ThaddyDecLength               100 msec
  5. JamieHowManyDigits            378 msec
  6. KeysDecimalDigitCount         558 msec

When checking for overflow, the JoshBitLength64 procedure causes an arithmetic overflow.

Josh

  • Hero Member
  • *****
  • Posts: 1424
Re: Standart function for length of decimal number
« Reply #39 on: October 19, 2025, 08:01:39 pm »
Hi ASerge,

I suspect the overflow checker is signed-integer–biased, so it sometimes flags perfectly valid unsigned math as overflow.

If you want for testing purposes to use the function directly then you could add a check within it ie?
Code: Pascal  [Select][+][-]
  1. function BitLength64(n:QWord):LongInt;inline;
  2. var t:QWord;
  3. begin
  4.   if n=0 then Exit(0);
  5.   t:=n;
  6.   t:=t or (t shr 1);
  7.   t:=t or (t shr 2);
  8.   t:=t or (t shr 4);
  9.   t:=t or (t shr 8);
  10.   t:=t or (t shr 16);
  11.   t:=t or (t shr 32);
  12.   Result:=deBruijn64[((t-(t shr 1))*$022FDD63CC95386D) shr 58]+1;
  13. end;

You could even turn off overflow checks for these inner functions.
ie
Code: Pascal  [Select][+][-]
  1. {$push}
  2. {$Q-}
  3. function BitLength64(n:QWord):LongInt;inline;
  4. var t:QWord;
  5. begin
  6.   t:=n;
  7.   t:=t or (t shr 1);
  8.   t:=t or (t shr 2);
  9.   t:=t or (t shr 4);
  10.   t:=t or (t shr 8);
  11.   t:=t or (t shr 16);
  12.   t:=t or (t shr 32);
  13.   Result:=deBruijn64[((t-(t shr 1))*$022FDD63CC95386D) shr 58]+1;
  14. end;
  15. {$pop}
  16. {$push}
  17. {$Q-}
  18. function BitLength32(n:LongWord):LongInt;inline;
  19. var t:LongWord;
  20. begin
  21.   t:=n;
  22.   t:=t or (t shr 1);
  23.   t:=t or (t shr 2);
  24.   t:=t or (t shr 4);
  25.   t:=t or (t shr 8);
  26.   t:=t or (t shr 16);
  27.   Result:=deBruijn32[((t-(t shr 1))*$077CB531) shr 27]+1;
  28. end;
  29. {$pop}


« Last Edit: October 19, 2025, 08:14:13 pm by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Josh

  • Hero Member
  • *****
  • Posts: 1424
Re: Standart function for length of decimal number
« Reply #40 on: October 19, 2025, 08:21:11 pm »
thought maybe direct casting would stop it without a if n=0 check

Code: Pascal  [Select][+][-]
  1. Result:=deBruijn64[QWord((t-(t shr 1))*QWord($022FDD63CC95386D)) shr 58]+1;          

If that works on your test data

probably best to add similar to the 32 version
Code: Pascal  [Select][+][-]
  1. Result:=deBruijn32[LongWord(((t-(t shr 1))*LongWord($077CB531))) shr 27]+1;

so the2 functions would read
Code: Pascal  [Select][+][-]
  1. {$push}
  2. {$Q-}
  3. function BitLength64(n:QWord):LongInt;inline;
  4. var t:QWord;
  5. begin
  6.   t:=n;
  7.   t:=t or (t shr 1);
  8.   t:=t or (t shr 2);
  9.   t:=t or (t shr 4);
  10.   t:=t or (t shr 8);
  11.   t:=t or (t shr 16);
  12.   t:=t or (t shr 32);
  13.   Result:=deBruijn64[QWord((t-(t shr 1))*QWord($022FDD63CC95386D)) shr 58]+1;
  14. end;
  15. {$pop}
  16. {$push}
  17. {$Q-}
  18. function BitLength32(n:LongWord):LongInt;inline;
  19. var t:LongWord;
  20. begin
  21.   t:=n;
  22.   t:=t or (t shr 1);
  23.   t:=t or (t shr 2);
  24.   t:=t or (t shr 4);
  25.   t:=t or (t shr 8);
  26.   t:=t or (t shr 16);
  27.   Result:=deBruijn32[LongWord(((t-(t shr 1))*LongWord($077CB531))) shr 27]+1;
  28. end;
  29. {$pop}          
« Last Edit: October 19, 2025, 08:34:12 pm by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

avk

  • Hero Member
  • *****
  • Posts: 814
Re: Standart function for length of decimal number
« Reply #41 on: October 20, 2025, 11:10:20 am »
Maybe
Code: Pascal  [Select][+][-]
  1. function JoshDecimalLength64(aValue: QWord): Integer; inline;
  2. const
  3.   POW10_64: array[0..19] of QWord = (
  4.                      0,               10,                100,                1000,
  5.                  10000,           100000,            1000000,            10000000,
  6.              100000000,       1000000000,        10000000000,        100000000000,
  7.          1000000000000,   10000000000000,    100000000000000,    1000000000000000,
  8.     10000000000000000,100000000000000000,1000000000000000000,10000000000000000000
  9.   );
  10. begin
  11.   Result := (Succ(ShortInt(BsrQWord(aValue))) * Integer(1233)) shr 12;
  12.   Inc(Result, Ord(aValue >= POW10_64[Result]));
  13. end;
  14.  

What about this version?

Josh

  • Hero Member
  • *****
  • Posts: 1424
Re: Standart function for length of decimal number
« Reply #42 on: October 20, 2025, 11:39:26 am »
hi AVk,

I  had thought of intel BSR and Arch CLZ,but I could not get my code to work, so i resorted to manual approach, I did not realize fpc had a crossplatform BsrQWord.

The code i had that failed,is below but think i had issues with register names, not used fpc asm for many many years,
If the QSRQword works it should be rapid as BSR is a single cycle instruction.

Code: Pascal  [Select][+][-]
  1. {$ifdef CPUAARCH64}
  2.   {$define HAS_CLZ}
  3. {$endif}
  4. {$ifdef CPUX86_64}
  5.   {$define HAS_BSR}
  6. {$endif}
  7. {$ifdef CPUX86}
  8.   {$define HAS_BSR}
  9. {$endif}
  10.  
  11. {$ifdef HAS_BSR}
  12. function BitLength64(n:UInt64):Integer;
  13. asm
  14.   BSR RAX, RDI
  15.   JZ  @zero
  16.   INC RAX
  17.   RET
  18. @zero:
  19.   XOR RAX, RAX
  20. end;
  21. {$elseif defined(HAS_CLZ)}
  22. function BitLength64(n:UInt64):Integer;
  23. asm
  24.   CLZ w1, x0
  25.   MOV w0, #64
  26.   SUB w0, w0, w1
  27. end;
  28. {$else}
  29. function BitLength64(n:QWord):LongInt;inline;
  30. var t:QWord;
  31. begin
  32.   t:=n;
  33.   t:=t or (t shr 1);
  34.   t:=t or (t shr 2);    
  35. ........
  36. end;
  37. {$endif}
« Last Edit: October 20, 2025, 11:54:20 am by Josh »
The best way to get accurate information on the forum is to post something wrong and wait for corrections.

Thaddy

  • Hero Member
  • *****
  • Posts: 18321
  • Here stood a man who saw the Elbe and jumped it.
Re: Standart function for length of decimal number
« Reply #43 on: October 20, 2025, 01:35:51 pm »
What is RDI doing there?
It should be something like
Code: Pascal  [Select][+][-]
  1. {$asmmode intel}
  2. function BitLength64(const n:UInt64):Integer;assembler;nostackframe;
  3. asm;
  4.   BSR RAX, RCX // or simply BSR RAX, n
  5.   JZ  @zero
  6.   INC RAX
  7.   RET
  8. @zero:
  9.   XOR RAX, RAX
  10. end;
Untested, but parameter is passed in RCX, not RDI, on X86_64
Same value as bsr intrinsic

Shorter is:
Code: Pascal  [Select][+][-]
  1. function BitLength64(const n:UInt64):integer;assembler;nostackframe;
  2. asm
  3.   XOR RAX,RAX // clean result
  4.   BSR RAX,RCX // because bsr on 0  with 0 = 0;
  5. end;

« Last Edit: October 20, 2025, 02:05:30 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Thaddy

  • Hero Member
  • *****
  • Posts: 18321
  • Here stood a man who saw the Elbe and jumped it.
Re: Standart function for length of decimal number
« Reply #44 on: October 20, 2025, 02:15:36 pm »
Ah, I see win vs Linux:
Linux is rdi, sorry:
Code: Pascal  [Select][+][-]
  1. {$asmmode intel}
  2. {$ifdef win64}
  3. function BitLength64(const n:UInt64):integer;assembler;nostackframe;
  4. asm
  5.   XOR EAX,EAX
  6.   BSR RAX,RCX
  7. end;
  8. {$else linux64}
  9. function BitLength64(const n:UInt64):integer;assembler;nostackframe;
  10. asm
  11.   XOR EAX,EAX
  12.   BSR RAX,RDI
  13. end;
  14. {$endif}
Tested win64 and lin64
« Last Edit: October 20, 2025, 02:17:10 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

 

TinyPortal © 2005-2018