Count := MyIntVar.ToString.Length;
Floating point Log will always be slower, it involves series calculation even when done in mathcoprocessor will be slow, and sending/getting results from coprocessor will probably be slower than integer operations unless number of digits is very big (>50) in which log10 might be faster.
cntIntToStr : 1328 ticks (Res = 10)
cntTypeHelper: 1359 ticks (Res = 10)
cntLog10 : 0047 ticks (Res = 10)
Notice that using typehelpers this is just a little bit slower than using classic Length(IntToStr()), but the Log10 is way faster.
Bart
Did not try a case statement.
@ASerge, I heard you did not like the source code of CntTbl. Wait until you see this one:What about Int64 and measurements?
@ASerge, I heard you did not like the source code of CntTbl. Wait until you see this one:What about Int64 and measurements?
and modified CntTbl:Modified CntTbl is inefficient, it should discard half at each comparisson so as to have fewer comparissons. It could be important to know which are most often used results, if 50% of cases are 6 digits, a well chosen case will be a lot faster.
should discard half at each comparisson so as to have fewer comparissons.
Since the constants are code generated (had to use GMP):It's not even compiled.
Modified CntTbl is inefficient, it should discard half at each comparisson so as to have fewer comparissons.You declare that the function is inefficient, but give arguments that are already implemented in this function. The depth of "if" is not more than 5, which is logical, because only 2^5 can close 19 characters.
Since the constants are code generated (had to use GMP):It's not even compiled.
You declare that the function is inefficient, but give arguments that are already implemented in this function. The depth of "if" is not more than 5, which is logical, because only 2^5 can close 19 characters.I meant using IF to split powers of 2 digits, which would give up to 32 digits with 5 comparissons, althought that would make sense only with real types. For int64 it's the same.
Give your effective example.
function cntBitly(Z: integer): integer;
There is still space for enhancement.
I meant using IF to split powers of 2 digits, which would give up to 32 digits with 5 comparissons, althought that would make sense only with real types. For int64 it's the same.I realized that you are not a reader, but a writer :)
Good catch. I most likely will not use an IF here. A simple AND and an additional entry into the arrays:function cntBitly(Z: integer): integer;
There is still space for enhancement.
It will fail for Z= 0 because: "BsrDWord: When the input is 0, the result is 255 (unsigned equivalent of -1)."
So it will try to get an out of range value in arrays. That will add another IF to function.
I got inspired this morning by the dumbest and probably quickest function:Nice idea, pretty fast.
I nice touch was making array of Word instead of Byte, I could have chosen longInt too but that would be a waste of Ram :)I like how you are concerned about wasting memory.
Another funny thing is InitializeArray which will do 10^10 mod operations, I wonder how much it will take...
Corrected the range check errors.OK. The testing project is included. Result:
Test 1
CntCaseTbl 93 ticks
CntTbl 63 ticks
cntBitly64 93 ticks
cntLog10 188 ticks
Test 2
CntCaseTbl 78 ticks
CntTbl 78 ticks
cntBitly64 78 ticks
cntLog10 172 ticks
Test 3
CntCaseTbl 94 ticks
CntTbl 62 ticks
cntBitly64 94 ticks
cntLog10 172 ticks
Test 4
CntCaseTbl 94 ticks
CntTbl 62 ticks
cntBitly64 94 ticks
cntLog10 187 ticks
Test 5
CntCaseTbl 78 ticks
CntTbl 78 ticks
cntBitly64 78 ticks
cntLog10 187 ticks
Test 6
CntCaseTbl 94 ticks
CntTbl 62 ticks
cntBitly64 94 ticks
cntLog10 171 ticks
Test 7
CntCaseTbl 94 ticks
CntTbl 62 ticks
cntBitly64 94 ticks
cntLog10 187 ticks
Advantages: No variables are used, and will take a constant (long) time because the absence of ELSEs.;D First, provide the finished project that is being compiled, and the time the test was run.
I want my price now. :)
... if abs(z)= maxInt then cntDumb:=20; end;
[…] orOMG. It’s surprising that I didn’t see that off-by-one-mistake when I read this topic back in 2018. It’s of course supposed to read like:
uses Math; function countZiff (inZahl : tNatZahl) : tNatZahl; begin Result := Floor(Log10(inZahl)); end;
I recently came across this problem and this is what I found to be the fastest function.
function CountDigits(Z: Int64): Integer; var X: UInt64; begin X := Abs(Z); if X < 10000000000 then if X < 10000 then if X < 100 then Result := 2 - Ord(X < 10) else Result := 4 - Ord(X < 1000) else if X < 100000000 then if X < 1000000 then Result := 6 - Ord(X < 100000) else Result := 8 - Ord(X < 10000000) else Result := 10 - Ord(X < 1000000000) else if X < 100000000000000 then if X < 1000000000000 then Result := 12 - Ord(X < 100000000000) else Result := 14 - Ord(X < 10000000000000) else if X < 1000000000000000000 then if X < 10000000000000000 then Result := 16 - Ord(X < 1000000000000000) else Result := 18 - Ord(X < 100000000000000000) else Result := 20 - Ord(X < 10000000000000000000); Inc(Result, Ord(Z < 0)); end;
As a bonus, it's also quite nice to read and understand due to the unintentional formatting.
By the way, since I see benchmark code using GetTickCount64. Don't do that - see https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-gettickcount64#remarks
Even though this still would not be 100% accurate for microbenchmarks such as this rather use QueryPerformanceCounter/QueryPerformanceFreq - or simply use TStopwatch - I think the FPC RTL should have that by now, doesn't it?
Unless there is some other Log10 that does not take a float like that in Math this is ten times slower than the "lot of code".I looked into the source of the math-unit, and there it's just a multiplication of the natural logarithm "ln" (which apparantely is a compiler intrinsic) with a "magic" number
i can't fathom how THAT could be slower than any loopingThere is no looping involved in any of the fastest functions but just at most 5 register compares and 4 conditional jumps.