Recent

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

LemonParty

  • Sr. Member
  • ****
  • Posts: 355
Standart function for length of decimal number
« on: October 17, 2025, 03:46:04 am »
Is there a standart function that return number of decimal digits in signed/unsigned integer?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

creaothceann

  • Full Member
  • ***
  • Posts: 198
Re: Standart function for length of decimal number
« Reply #1 on: October 17, 2025, 07:22:36 am »
Afaik no. Just use Length(IntToStr(Abs(number))).

« Last Edit: October 17, 2025, 08:30:48 am by creaothceann »
And don't start an argument, I am right.

Warfley

  • Hero Member
  • *****
  • Posts: 2020
Re: Standart function for length of decimal number
« Reply #2 on: October 17, 2025, 07:54:59 am »
What you are searching for is the logarithm, especially for base 10 Log10. Round the result down and add 1 and you have your length:
Code: Pascal  [Select][+][-]
  1. Trunc(Log10(Num)) + 1
Alternatively:
Code: Pascal  [Select][+][-]
  1. function IntLog10(v: QWord): Integer; inline;
  2. begin
  3.   Result:=0;
  4.   While v>=10 do
  5.   begin
  6.     Inc(Result);
  7.     v := v div 10;
  8.   end;
  9. end;

Thausand

  • Sr. Member
  • ****
  • Posts: 391
Re: Standart function for length of decimal number
« Reply #3 on: October 17, 2025, 08:16:20 am »
Afaik no. Just use Length(IntToStr(number)).
or make use typehelpers: abs(number).ToString.Length

What you are searching for is the logarithm, especially for base 10 Log10. Round the result down and add 1 and you have your length:
Code: Pascal  [Select][+][-]
  1. Trunc(Log10(Num)) + 1
Give problem exception zero and negative. Fix and use abs number and make test zero and give result 1

 :)

Zvoni

  • Hero Member
  • *****
  • Posts: 3135
Re: Standart function for length of decimal number
« Reply #4 on: October 17, 2025, 08:19:23 am »
What you are searching for is the logarithm, especially for base 10 Log10. Round the result down and add 1 and you have your length:
Alternatively:
Code: Pascal  [Select][+][-]
  1. function IntLog10(v: QWord): Integer; inline;
  2. begin
  3.   Result:=0;
  4.   While v>=10 do
  5.   begin
  6.     Inc(Result);
  7.     v := v div 10;
  8.   end;
  9. end;
Would have to disagree on the alternative.
Pass "0" and your Result is 0
but "0" is still 1 Digit of "Length"
Would have used Repeat Until v=0

And agree with Thausand
Code: Pascal  [Select][+][-]
  1. function IntLog10(v: QWord): Integer; inline;
  2. begin
  3.   Result:=0;
  4.   Repeat  
  5.     Inc(Result);
  6.     v := Abs(v) div 10;
  7.   Until v=0;
  8. end;
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Thaddy

  • Hero Member
  • *****
  • Posts: 18306
  • Here stood a man who saw the Elbe and jumped it.
Re: Standart function for length of decimal number
« Reply #5 on: October 17, 2025, 03:25:11 pm »
fast alternative with lut:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode objfpc}{$endif}
  2. function IntLog10(n: Cardinal): Integer;inline;
  3. type
  4.   range = 0..9;
  5. const
  6.   RevPowers: array[0..9] of Cardinal = (
  7.     1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1);
  8. var
  9.   i: range;
  10. begin
  11.   if n = 0 then exit(-1);
  12.   Result := 0;
  13.   for i in range do
  14.     if n >= RevPowers[i] then exit(high(range)-i);
  15. end;
  16.  
  17.  
  18. begin
  19.   writeln(intlog10(1001));
  20. end.
OTOH, one compare, least amount of branching, compiler friendly.

32 bit only.
« Last Edit: October 17, 2025, 03:44:14 pm by Thaddy »
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

LemonParty

  • Sr. Member
  • ****
  • Posts: 355
Re: Standart function for length of decimal number
« Reply #6 on: October 17, 2025, 03:58:20 pm »
Good idea Thaddy.
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

MathMan

  • Sr. Member
  • ****
  • Posts: 434
Re: Standart function for length of decimal number
« Reply #7 on: October 17, 2025, 04:32:00 pm »
Is there a standart function that return number of decimal digits in signed/unsigned integer?

Fortunately that has been researched already. I suggest looking at https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-faster/

The solution presented is extremely fast for UInt32 and - once you understood the algorithm - extendable to UInt64.

Regards,
MathMan

440bx

  • Hero Member
  • *****
  • Posts: 5805
Re: Standart function for length of decimal number
« Reply #8 on: October 17, 2025, 04:59:53 pm »
Just a simple comment that isn't related to computing the number of digits in a number.

In the code:
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode objfpc}{$endif}
  2. function IntLog10(n: Cardinal): Integer;inline;
  3. type
  4.   range = 0..9;
  5. const
  6.   RevPowers: array[0..9] of Cardinal = (
  7.     1000000000,100000000,10000000,1000000,100000,10000,1000,100,10,1);
  8. var
  9.   i: range;
  10. begin
  11.   if n = 0 then exit(-1);
  12.   Result := 0;
  13.   for i in range do
  14.     if n >= RevPowers[i] then exit(high(range)-i);
  15. end;
  16.  
  17.  
  18. begin
  19.   writeln(intlog10(1001));
  20. end.
  21.  
It is important to use the type "range" in the definition of the array otherwise the "for i in range" does not guarantee that the full array range is covered since the array isn't defined using the "range" type.

IOW, line 6 should be:
Code: Pascal  [Select][+][-]
  1.   RevPowers: array[range] of Cardinal = (
  2.  
FPC v3.2.2 and Lazarus v4.0rc3 on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 18306
  • Here stood a man who saw the Elbe and jumped it.
Re: Standart function for length of decimal number
« Reply #9 on: October 17, 2025, 05:38:06 pm »
 :D Yes.
Due to censorship, I changed this to "Nelly the Elephant". Keeps the message clear.

Warfley

  • Hero Member
  • *****
  • Posts: 2020
Re: Standart function for length of decimal number
« Reply #10 on: October 17, 2025, 05:44:58 pm »
What you are searching for is the logarithm, especially for base 10 Log10. Round the result down and add 1 and you have your length:
Alternatively:
Code: Pascal  [Select][+][-]
  1. function IntLog10(v: QWord): Integer; inline;
  2. begin
  3.   Result:=0;
  4.   While v>=10 do
  5.   begin
  6.     Inc(Result);
  7.     v := v div 10;
  8.   end;
  9. end;
Would have to disagree on the alternative.
Pass "0" and your Result is 0
but "0" is still 1 Digit of "Length"
Would have used Repeat Until v=0
Well yeah I didn't mean that this computes the length directly, but as the name suggests it's an integer based log10, so basically an alternative to trunc(log10(n)) to avoid having to deal with floats which is very slow. In my tests doing the IntLog10 above is roughly 3 times faster than Trunc(Log10(x))
To compute the length you still need to add 1

LemonParty

  • Sr. Member
  • ****
  • Posts: 355
Re: Standart function for length of decimal number
« Reply #11 on: October 17, 2025, 08:20:42 pm »
Is there a standart function that return number of decimal digits in signed/unsigned integer?

Fortunately that has been researched already. I suggest looking at https://lemire.me/blog/2021/06/03/computing-the-number-of-digits-of-an-integer-even-faster/

The solution presented is extremely fast for UInt32 and - once you understood the algorithm - extendable to UInt64.

Regards,
MathMan
I translated code into Pascal. But I don't know how to implemet it for 64 bit.
Code: Pascal  [Select][+][-]
  1. uses Math;
  2.  
  3. function DecLength(i: DWord): SizeUInt;inline;
  4. const
  5.   CTable: array [0..31] of QWord = (
  6.     4294967296,  8589934582,  8589934582,  8589934582,
  7.     12884901788, 12884901788, 12884901788, 17179868184,
  8.     17179868184, 17179868184, 21474826480, 21474826480,
  9.     21474826480, 21474826480, 25769703776, 25769703776,
  10.     25769703776, 30063771072, 30063771072, 30063771072,
  11.     34349738368, 34349738368, 34349738368, 34349738368,
  12.     38554705664, 38554705664, 38554705664, 41949672960,
  13.     41949672960, 41949672960, 42949672960, 42949672960
  14.   );
  15. begin
  16.   if i = 0 then
  17.     Result:= 1
  18.   else
  19.     Result:= (i + CTable[Trunc(Log2(i))]) shr 32;
  20. end;
  21.  
  22. function DecLength(i: LongInt): SizeUInt;inline;
  23. begin
  24.   if i < 0 then
  25.     Result:= 1 + DecLength(DWord(-i))
  26.   else
  27.     Result:= DecLength(DWord(i));
  28. end;
  29.  
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

Warfley

  • Hero Member
  • *****
  • Posts: 2020
Re: Standart function for length of decimal number
« Reply #12 on: October 17, 2025, 08:58:29 pm »
I translated code into Pascal. But I don't know how to implemet it for 64 bit.
You used trunc(log2(x)), which involves floating point operations which are extremely slow. I benchmarked all of the codes provided here:
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. uses sysutils,Math;
  6.  
  7. function DecLength(i: DWord): SizeUInt;inline;
  8. const
  9.   CTable: array [0..31] of QWord = (
  10.     4294967296,  8589934582,  8589934582,  8589934582,
  11.     12884901788, 12884901788, 12884901788, 17179868184,
  12.     17179868184, 17179868184, 21474826480, 21474826480,
  13.     21474826480, 21474826480, 25769703776, 25769703776,
  14.     25769703776, 30063771072, 30063771072, 30063771072,
  15.     34349738368, 34349738368, 34349738368, 34349738368,
  16.     38554705664, 38554705664, 38554705664, 41949672960,
  17.     41949672960, 41949672960, 42949672960, 42949672960
  18.   );
  19. begin
  20.   if i = 0 then
  21.     Result:= 1
  22.   else
  23.     Result:= (i + CTable[Trunc(Log2(i))]) shr 32;
  24. end;
  25.  
  26. function IntLog10(v: DWord): SizeUInt; inline;
  27. begin
  28.   Result:=0;
  29.   While v>=10 do
  30.   begin
  31.     Inc(Result);
  32.     v := v div 10;
  33.   end;
  34. end;
  35.  
  36. function TruncLog10(v: DWord): SizeUInt; inline;
  37. begin
  38.   if v=0 then
  39.     Result:=0
  40.   else
  41.     Result:=trunc(log10(v));
  42. end;
  43.  
  44. function StrLen(v: DWord): SizeUInt; inline;
  45. begin
  46.   Result:=Length(IntToStr(v));
  47. end;
  48.  
  49. function LookUp(v: DWord): SizeInt; inline;
  50. const
  51.   LATable: array [2..10] of QWord = (10,  100,  1000,  10000, 100000, 1000000, 10000000, 100000000, 1000000000);
  52. begin
  53.   for Result:=High(LATable) downto Low(LATable) do
  54.     if v >= LATable[Result] then
  55.       Exit;
  56.   Result:=1;
  57. end;
  58.  
  59. function Hardcode(v: DWord): SizeInt; inline;
  60. begin
  61.   case v of
  62.   0..9: Result:=1;
  63.   10..99: Result:= 2;
  64.   100..999: Result:=3;
  65.   1000..9999: Result:=4;
  66.   10000..99999: Result:=5;
  67.   100000..999999: Result:=6;
  68.   1000000..9999999: Result:=7;
  69.   10000000..99999999: Result:=8;
  70.   100000000..999999999: Result:=9;
  71.   otherwise Result:=10;
  72.   end;
  73. end;
  74.  
  75. const
  76.   laps=100000000;
  77. var
  78.   s: QWord;
  79.   x, i: Integer;
  80. begin
  81.   x:=0;
  82.   s:=GetTickCount64;
  83.   for i:=1 to laps do
  84.     x:=x+DecLength(Random(100000000));
  85.   WriteLn('DecLength: ', GetTickCount64-s);
  86.   s:=GetTickCount64;
  87.   for i:=1 to laps do
  88.     x:=x+IntLog10(Random(100000000)) + 1;
  89.   WriteLn('IntLog10: ', GetTickCount64-s);
  90.   s:=GetTickCount64;
  91.   for i:=1 to laps do
  92.     x:=x+TruncLog10(Random(100000000)) + 1;
  93.   WriteLn('TruncLog10: ', GetTickCount64-s);
  94.   s:=GetTickCount64;
  95.   for i:=1 to laps do
  96.     x:=x+StrLen(Random(100000000));
  97.   WriteLn('StrLen: ', GetTickCount64-s);
  98.   s:=GetTickCount64;
  99.   for i:=1 to laps do
  100.     x:=x+LookUp(Random(100000000));
  101.   WriteLn('LookUp: ', GetTickCount64-s);
  102.   s:=GetTickCount64;
  103.   for i:=1 to laps do
  104.     x:=x+Hardcode(Random(100000000));
  105.   WriteLn('Hardcode: ', GetTickCount64-s);
  106. end.
  107.  
Code: Text  [Select][+][-]
  1. DecLength: 3683
  2. IntLog10: 555
  3. TruncLog10: 3928
  4. StrLen: 2140
  5. LookUp: 398
  6. Hardcode: 421
On O4 not surprisingly the two implementations using floats are by far the slowest. Whats interesting is that the hardcoded case statement is worse than the lookup. The extremely naive IntLog10 implementation is nearly as fast as those hardcoded or lookup implementations.

If I replace the trunc(log2(i)) with this:
Code: Pascal  [Select][+][-]
  1. function intlog2(v: QWord): Integer; inline;
  2. begin
  3.   Result:=0;
  4.   while v>1 do
  5.   begin
  6.     Inc(Result);
  7.     v:=v shr 1;
  8.   end;
  9. end;
The result is
Code: Text  [Select][+][-]
  1. DecLength: 1078
  2. IntLog10: 555
  3. TruncLog10: 3930
  4. StrLen: 2180
  5. LookUp: 367
  6. Hardcode: 416
Instead.

Sometimes the most "stupid" solutions are the best ones
« Last Edit: October 17, 2025, 09:08:05 pm by Warfley »

LemonParty

  • Sr. Member
  • ****
  • Posts: 355
Re: Standart function for length of decimal number
« Reply #13 on: October 17, 2025, 09:11:36 pm »
Which one is the LookUp method?
Lazarus v. 4.99. FPC v. 3.3.1. Windows 11

cdbc

  • Hero Member
  • *****
  • Posts: 2464
    • http://www.cdbc.dk
Re: Standart function for length of decimal number
« Reply #14 on: October 17, 2025, 09:49:59 pm »
Code: Pascal  [Select][+][-]
  1. function LookUp(v: DWord): SizeInt; inline;
  2. const
  3.   LATable: array [2..10] of QWord = (10,  100,  1000,  10000, 100000, 1000000, 10000000, 100000000, 1000000000);
  4. begin
  5.   for Result:=High(LATable) downto Low(LATable) do
  6.     if v >= LATable[Result] then
  7.       Exit;
  8.   Result:=1;
  9. end;
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6 -> FPC 3.2.2 -> Lazarus 4.0 up until Jan 2025 from then on it's both above &: KDE6/QT6 -> FPC 3.3.1 -> Lazarus 4.99

 

TinyPortal © 2005-2018