Code: Select all
;I always wanted a random yes/no function,
;but Random() is a pseudo-random generator,
;and it has some overhead too.
;After contemplating using date/time, or high res timers,
;I remember the CPU Time Stamp Counter (TSC),
;which has a tendancy to be erratic, especially on modern systems,
;this is why Microsoft advice QueryPerformanceCounter for timings instead,
;but for hours use an unreliable high res CPU cycle counter is perfect.
EnableExplicit
Procedure.i RandomBit()
!RDTSC ;Read the CPU Time Stamp Counter
!AND EAX,$1 ;We only want the least significant bit as that changes the most.
ProcedureReturn ;Return the EAX register content. (0 or 1 in this case)
EndProcedure
;An alternative would be using QueryPerformanceCounter,
;but using that has more overhead.
;Minimum CPU supported with the RDTSC call is original Pentium,
;and CPU's fully compatible to it, which includes pretty much
;every x86 CPU relased the last 10+ years.
;Works on x64 as well, although using 64bit register in that case "might" be faster than this.
Define.i o,z,r,i
DisableDebugger
For i=1 To 10000
If RandomBit()
o+1
Else
z+1
EndIf
Delay(1) ;Due to CPU caching we need to spread the calls apart,
;otherwise we end up with many calls in too close proximity
;possibly causing a bias towards 1 or 0.
;Even a delay of 0 ()task switch may be too tight,
;a delay of 1ms provides more consistent results,
;and is probably closer to real use as implemetend in games and applications.
Next
EnableDebugger
Debug o
Debug z
;You should get close to even numbers on average (50%/50%) in the above test,
;but you will also see abnormalies or even slight biases,
;the reason for this is many: caching, cores, brand, speed, processes/threads, programs running,
;system uptime, CPU speed stepping.
;Considering how "busy" CPU's are on a PC, the cycle count is constantly changing and very rapidly,
;and it changes at unknown intervals, all this makes it perfect as the base for a random function.
;Note! This is "random" we are talking about, not pseudo-random like Random() or perfect entropy (impossible really)
;RadomBits() is perfectly random in that, there is no way to predict at all what that least signficant bit will be.
;So now you can make your "AI" seemingly behave randomly (or unexpectedly) in Yes/no, Positive/Negative, On/of situations,
;shoot/do not shoot, the player has been seen/not seen, a car is about to drive by/or not drive by.
;In a game or application, depending on your needs, you may also want to track the last n choices,
;just to avoid behaviour that migth seem tiresome to the player or user. (sort of like a pseudo-random function).
;Part of what makes RandomBit() so great is that combined with the time when it's called makes it even more unpredictable.