So the first 3 numbers are identical.
Unless you have a real time OS,
and write the code to special rules for getting real time results, you will have variances. E.g. the OS scheduler may interrupt the code.
Now() is also not the most exact timer.
Then, your loops are not the same, you are comparing apples to oranges.
The for loop runs to "High(Int64). Well it may exit earlier. It has
TWO exit conditions.
for Count := 1 to High(Int64) do
if MilliSecondsBetween(Now, StartTime) >= 1000 then Break;
while MilliSecondsBetween(Now, StartTime) < 1000 do Inc(Count);
You don't check the "High(Int64)" exit condition. So this is completely different code that is run. Comparing the time to the "for" loop is meaningless.
Take the "MilliSecondsBetween(Now, StartTime) >= 1000" out of both loops, and the "for" loop will end, but the "while" loop will loop forever (overflowing Count eventually).
The "for in" has significantly less calls to "MilliSecondsBetween(Now, StartTime) >= 1000" => so of course it is faster. But then "A:=3.14;" is also significantly faster than "A := Round(Calculate1000DigitsOfPiFromScratch,2);".
Depending on your CPU there may be other factors. With loops that small many modern INTEL/AMD cpu can be faster if the loop is aligned at a 32byte boundary. Putting the loops one after another may give them different alignments. But even putting each in a procedure of its own, will at best do 16byte alignment. You would need to
- specify the desired alignment
- benchmark with different settings
And, running them one by one,... Many cpu will have a "Boost" mode that lasts for a short time only. So some part of your code may run at significantly higher CPU clock that the rest.
In other words, benchmarking can be very complex.
Mind you, its possible that accounting for align and boost will get the same results. Or not...
But at least make the code for all loops
"do the same work"